Ejemplo n.º 1
0
/** Write file containing only cut atoms and energies as charges. */
int Action_Pairwise::WriteCutFrame(int frameNum, Topology const& Parm, AtomMask const& CutMask, 
                                   Darray const& CutCharges,
                                   Frame const& frame, std::string const& outfilename) 
{
  if (CutMask.Nselected() != (int)CutCharges.size()) {
    mprinterr("Error: WriteCutFrame: # of charges (%u) != # mask atoms (%i)\n",
              CutCharges.size(), CutMask.Nselected());
    return 1;
  }
  Frame CutFrame(frame, CutMask);
  Topology* CutParm = Parm.modifyStateByMask( CutMask );
  if (CutParm == 0) return 1;
  // Set new charges
  for (int i = 0; i != CutParm->Natom(); i++)
    CutParm->SetAtom(i).SetCharge( CutCharges[i] );
  int err = 0;
  Trajout_Single tout;
  if (tout.PrepareTrajWrite(outfilename, "multi", CutParm, CoordinateInfo(), 1,
                            TrajectoryFile::MOL2FILE))
  {
    mprinterr("Error: Could not set up cut mol2 file %s\n", outfilename.c_str());
    err = 1;
  } else {
    tout.WriteSingle(frameNum, CutFrame);
    tout.EndTraj();
  }
  delete CutParm;
  return err;
}
Ejemplo n.º 2
0
/** Print atoms for which the cumulative energy satisfies the given
  * cutoffs. Also create MOL2 files containing those atoms.
  */
int Action_Pairwise::PrintCutAtoms(Frame const& frame, int frameNum, EoutType ctype,
                                   Darray const& Earray, double cutIn)
{
  AtomMask CutMask;  // Hold atoms that satisfy the cutoff
  Darray CutCharges; // Hold evdw/eelec corresponding to CutMask atoms.

  if (Eout_ != 0) {
    if (nb_calcType_==COMPARE_REF)
      Eout_->Printf("\tPAIRWISE: Cumulative d%s:", CalcString[ctype]);
    else
      Eout_->Printf("\tPAIRWISE: Cumulative %s:", CalcString[ctype]);
    Eout_->Printf(" %s < %.4f, %s > %.4f\n", CalcString[ctype], -cutIn,
                 CalcString[ctype], cutIn);
  }
  for (AtomMask::const_iterator atom = Mask0_.begin(); atom != Mask0_.end(); ++atom)
  {
    if (fabs(Earray[*atom]) > cutIn)
    {
      if (Eout_ != 0) 
        Eout_->Printf("\t\t%6i@%s: %12.4f\n", *atom+1,
                    (*CurrentParm_)[*atom].c_str(), Earray[*atom]);
      CutMask.AddAtom(*atom);
      CutCharges.push_back(Earray[*atom]);
    }
  }
  // Write mol2 with atoms satisfying cutoff
  if (!mol2Prefix_.empty() && !CutMask.None()) {
    if (WriteCutFrame(frameNum, *CurrentParm_, CutMask, CutCharges, 
                      frame, mol2Prefix_ + CutName[ctype])) 
      return 1;
  }

  return 0;
}
Ejemplo n.º 3
0
// Action_Matrix::FillMassArray()
Action_Matrix::Darray Action_Matrix::FillMassArray(Topology const& currentParm, 
                                                   AtomMask const& mask) const
{
  Darray mass;
  mass.reserve( mask.Nselected() );
  for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) 
    mass.push_back( currentParm[ *atom ].Mass() );
  return mass;
}
Ejemplo n.º 4
0
float cunorm2 (const Darray<float>& ary)
{
	ary.deviceSet();
	float ret;
	CUBLAS_SAFE_CALL(
			cublasSnrm2 (DeviceManager::handle,
						 ary.size(),
						 ary.dev_data,
						 1,
						 &ret)
	);
	return ret;
}
Ejemplo n.º 5
0
double cunorm2 (const Darray<double>& ary)
{
	ary.deviceSet();
	double ret;
	CUBLAS_SAFE_CALL(
			cublasDnrm2 (DeviceManager::handle,
						 ary.size(),
						 ary.dev_data,
						 1,
						 &ret)
	);
	return ret;
}
Ejemplo n.º 6
0
// Analysis_TI::Calc_Nskip()
int Analysis_TI::Calc_Nskip() {
  // sum: Hold the results of integration for each curve (skip value)
  Darray sum(nskip_.size(), 0.0);
  // lastSkipPoint: Points after which averages can be recorded
  Iarray lastSkipPoint;
  for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it)
    lastSkipPoint.push_back( *it - 1 );
  // Loop over input data sets. 
  for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) {
    DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) );
    if (CheckSet(ds)) return 1; 
    // Determine if skip values are valid for this set.
    Darray Npoints; // Number of points after skipping
    for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it) {
      int np = (int)ds.Size() - *it;
      if (np < 1) {
        mprinterr("Error: Skipped too many points (set '%s' size is %zu)\n",ds.legend(),ds.Size());
        return 1;
      }
      Npoints.push_back((double)np);
    }
    // Calculate averages for each value of skip
    Darray avg(nskip_.size(), 0.0);
    for (int i = 0; i != (int)ds.Size(); i++) {
      for (unsigned int j = 0; j != nskip_.size(); j++)
        if (i > lastSkipPoint[j])
          avg[j] += ds.Dval( i );
    }
    // Store average DV/DL for each value of skip
    for (unsigned int j = 0; j != nskip_.size(); j++) {
      avg[j] /= Npoints[j];
      if (debug_ > 0)
        mprintf("\t%s Skip= %i <DV/DL>= %g\n", ds.legend(), nskip_[j], avg[j]);
      DataSet_Mesh& CR = static_cast<DataSet_Mesh&>( *(curve_[j]) );
      CR.AddXY(xval_[idx], avg[j]);
      if (mode_ == GAUSSIAN_QUAD)
        sum[j] += (wgt_[idx] * avg[j]);
    }
  } // END loop over input data sets
  if (mode_ == TRAPEZOID) Integrate_Trapezoid(sum);
  // Store final TI integration values.
  DataSet_Mesh& DA = static_cast<DataSet_Mesh&>( *dAout_ );
  DA.ModifyDim(Dimension::X).SetLabel("PtsSkipped");
  for (unsigned int j = 0; j != nskip_.size(); j++)
    DA.AddXY(nskip_[j], sum[j]);

  return 0;
}
Ejemplo n.º 7
0
Analysis::RetType Analysis_TI::Analyze() {
  Darray sum(nskip_.size(), 0.0);
  DataSet_Mesh& DA = static_cast<DataSet_Mesh&>( *dAout_ );
  Iarray lastSkipPoint; // Points after which averages can be recorded
  for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it)
    lastSkipPoint.push_back( *it - 1 );
  // Run for multiple skip values, helps test convergences.
  for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) {
    DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) );
    if (ds.Size() < 1) {
      mprinterr("Error: Set '%s' is empty.\n", ds.legend());
      return Analysis::ERR;
    }
    // Determine if skip values are valid for this set.
    Darray Npoints; // Number of points after skipping
    for (Iarray::const_iterator it = nskip_.begin(); it != nskip_.end(); ++it) {
      int np = (int)ds.Size() - *it;
      if (np < 1) {
        mprinterr("Error: Skipped too many points (set '%s' size is %zu)\n",ds.legend(),ds.Size());
        return Analysis::ERR;
      }
      Npoints.push_back((double)np);
    }
    // Calculate averages for each value of skip
    Darray avg(nskip_.size(), 0.0);
    for (int i = 0; i != (int)ds.Size(); i++) {
      for (unsigned int j = 0; j != nskip_.size(); j++)
        if (i > lastSkipPoint[j])
          avg[j] += ds.Dval( i );
    }
    // Store average DV/DL for each value of skip
    for (unsigned int j = 0; j != nskip_.size(); j++) {
      avg[j] /= Npoints[j];
      //mprintf("\t<DV/DL>=%g\n", avg);
      DataSet_Mesh& CR = static_cast<DataSet_Mesh&>( *(curve_[j]) );
      CR.AddXY(quad_[idx], avg[j]);
      sum[j] += (wgt_[idx] * avg[j]);
    }
  }
  for (unsigned int j = 0; j != nskip_.size(); j++)
    DA.AddXY(nskip_[j], sum[j]);

  return Analysis::OK;
}
Ejemplo n.º 8
0
/** For final Y values vs given (presumably initial) Y values, calculate
  * correlation coefficient, chi-squared, Theil's U, and RMS percent 
  * error.
  */
int CurveFit::Statistics(Darray const& Yvals,
                         double& corr, double& ChiSq, 
                         double& TheilU, double& rms_percent_error) const
{
  if (finalY_.empty() || Yvals.size() != finalY_.size())
    return 9;
  int err_val = 0;
  unsigned int Nvals = Yvals.size();
  // Correlation coefficient
  corr = 0.0;
  if (Nvals > 1) {
    double mean0, mean1, stdev0, stdev1;
    CalcMeanStdev(finalY_, mean0, stdev0);
    CalcMeanStdev(Yvals,   mean1, stdev1);
    if (stdev0 > 0.0 && stdev1 > 0.0) {
      for (unsigned int n = 0; n != Nvals; n++)
        corr += (finalY_[n] - mean0) * (Yvals[n] - mean1);
      corr /= ((double)(Nvals - 1) * stdev0 * stdev1);
    }
  }
  ChiSq = 0.0;
  double Y2 = 0.0;
  bool setHasZero = false;
  for (unsigned int n = 0; n != Nvals; n++) {
    double diff = finalY_[n] - Yvals[n];
    ChiSq += (diff * diff);
    Y2 += (Yvals[n] * Yvals[n]);
    if (Yvals[n] == 0.0)
      setHasZero = true;
  }
  TheilU = sqrt(ChiSq / Y2);
  rms_percent_error = 0.0;
  if (!setHasZero) {
    for (unsigned int n = 0; n != Nvals; n++) {
      double diff = finalY_[n] - Yvals[n];
      rms_percent_error += (diff * diff) / (Yvals[n] * Yvals[n]);
    }
    rms_percent_error = sqrt( rms_percent_error / (double)Nvals );
  } else
    err_val = 10;
  return err_val;
}
Ejemplo n.º 9
0
// CurveFit::CalcMeanStdev()
void CurveFit::CalcMeanStdev(Darray const& Vals, double& mean, double& stdev) const
{
  mean = 0.0;
  for (Darray::const_iterator val = Vals.begin(); val != Vals.end(); ++val)
    mean += *val;
  mean /= (double)Vals.size();
  stdev = 0.0;
  if (Vals.size() > 1) {
    for (Darray::const_iterator val = Vals.begin(); val != Vals.end(); ++val)
    {
      double diff = mean - *val;
      stdev += (diff * diff);
    }
    stdev = sqrt( stdev / (double)(Vals.size() - 1) );
  }
}
Ejemplo n.º 10
0
Darray<float> cudot (const Darray<float>& lhs, const Darray<float>& rhs)
{
	// context check
	CHECK_EQ(lhs.getDeviceManager().getDeviceID(), rhs.getDeviceManager().getDeviceID());
	
	CHECK_EQ(lhs.ndim(), rhs.ndim());
	CHECK_LT(lhs.ndim(), 3);
	CHECK_LT(rhs.ndim(), 3);

	Darray<float> ret;

	if (lhs.ndim()==1 && rhs.ndim()==1)
	{
		// shape check
		CHECK_EQ(lhs.size(), rhs.size());
		ret = Darray<float>(lhs.getDeviceManager(), {1});
		
		// using cublas sdot
		lhs.deviceSet();
		cublasSdot (DeviceManager::handle,
				    lhs.size(),
				    lhs.data,
				    1,
				    rhs.data,
				    1,
				    ret.data);
	}
	// 2D matrix dot
	else if (lhs.ndim()==2 && rhs.ndim()==2)
	{
		// shape check
		CHECK_EQ(lhs.shape()[1], rhs.shape()[0]);
		ret = Darray<float>(lhs.getDeviceManager(), {lhs.shape()[0], rhs.shape()[1]});
		
		// using cublas sgemm
		lhs.deviceSet();
		const float alpha = 1.;
		const float beta = 0.;
		CUBLAS_SAFE_CALL(
		cublasSgemm (DeviceManager::handle,
					CUBLAS_OP_N,
					CUBLAS_OP_N,
					lhs.shape()[0],
					rhs.shape()[1],
					lhs.shape()[1],
					&alpha,
					lhs.dev_data,
					lhs.shape()[0],
					rhs.dev_data,
					rhs.shape()[0],
					&beta,
					ret.dev_data,
					ret.shape()[0])
		);
	}
	return ret;
}
Ejemplo n.º 11
0
// Analysis_TI::Calc_Increment()
int Analysis_TI::Calc_Increment() {
  // Determine max points if not given.
  int maxpts = avg_max_;
  if (maxpts == -1) {
    for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) {
      DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) );
      if (maxpts == -1)
        maxpts = (int)ds.Size();
      else if (maxpts != (int)ds.Size()) {
        mprintf("Warning: # points in '%s' (%zu) is different than %i.\n",
                ds.legend(), ds.Size(), maxpts);
        maxpts = std::min( maxpts, (int)ds.Size() );
        mprintf("Warning:   Will only use %i points.\n", maxpts);
      }
    }
  }
  if (maxpts < 1) {
    mprinterr("Error: Max points to use is < 1.\n");
    return 1;
  }
  if (avg_skip_ >= maxpts) {
    mprinterr("Error: 'avgskip' (%i) > max (%i).\n", avg_skip_, maxpts);
    return 1;
  }
  // sum: Hold the results of integration for each curve (increment)
  Darray sum;
  // points: Hold point values at which each avg is being calculated
  Iarray points;
  // Loop over input data sets. 
  for (unsigned int idx = 0; idx != input_dsets_.size(); idx++) {
    DataSet_1D const& ds = static_cast<DataSet_1D const&>( *(input_dsets_[idx]) );
    if (CheckSet(ds)) return 1; 
    // Calculate averages for each increment
    Darray avg;
    Iarray increments;
    int count = 0;
    int endpt = maxpts -1;
    double currentSum = 0.0;
    if (debug_ > 0) mprintf("DEBUG: Lambda %g\n", xval_[idx]);
    for (int pt = avg_skip_; pt != maxpts; pt++)
    {
      currentSum += ds.Dval(pt);
      count++;
      if (count == avg_increment_ || pt == endpt) {
        avg.push_back( currentSum / ((double)(pt - avg_skip_ + 1)) );
        increments.push_back(pt+1);
        if (debug_ > 0)
          mprintf("DEBUG:\t\tAvg from %i to %i: %g\n", avg_skip_+1, pt+1, avg.back());
        count = 0;
      }
    }
    if (sum.empty()) {
      sum.resize(avg.size());
      points = increments;
    } else if (sum.size() != avg.size()) {
      mprinterr("Error: Different # of increments for set '%s'; got %zu, expected %zu.\n",
                ds.legend(), avg.size(), sum.size());
      return 1;
    }
    // Create increment curve data sets
    if (curve_.empty()) {
      MetaData md(dAout_->Meta().Name(), "TIcurve");
      for (unsigned int j = 0; j != avg.size(); j++) {
        md.SetIdx( increments[j] );
        DataSet* ds = masterDSL_->AddSet(DataSet::XYMESH, md);
        if (ds == 0) return Analysis::ERR;
        ds->ModifyDim(Dimension::X).SetLabel("Lambda");
        ds->SetLegend( md.Name() + "_Skip" + integerToString(increments[j]) );
        if (curveout_ != 0) curveout_->AddDataSet( ds );
        curve_.push_back( ds );
      }
    }
    for (unsigned int j = 0; j != avg.size(); j++) {
      DataSet_Mesh& CR = static_cast<DataSet_Mesh&>( *(curve_[j]) );
      CR.AddXY(xval_[idx], avg[j]);
      if (mode_ == GAUSSIAN_QUAD)
        sum[j] += (wgt_[idx] * avg[j]);
    }
  } // END loop over data sets
  if (mode_ == TRAPEZOID) Integrate_Trapezoid(sum);
  // Store final integration values
  DataSet_Mesh& DA = static_cast<DataSet_Mesh&>( *dAout_ );
  DA.ModifyDim(Dimension::X).SetLabel("Point");
  for (unsigned int j = 0; j != points.size(); j++)
    DA.AddXY(points[j], sum[j]);

  return 0;
}
Ejemplo n.º 12
0
/** Given an array of already set up data sets (from e.g. input data files)
  * and optional X values, add the sets to this list if they do not exist
  * or append any existing sets.
  */
int DataSetList::AddOrAppendSets(std::string const& XlabelIn, Darray const& Xvals,
                                 DataListType const& Sets)
{
  if (debug_ > 0)
    mprintf("DEBUG: Calling AddOrAppendSets for %zu sets, %zu X values, Xlabel= %s.\n",
            Sets.size(), Xvals.size(), XlabelIn.c_str());
  if (Sets.empty()) return 0; // No error for now.
  // If no X label assume 'Frame' for backwards compat.
  std::string Xlabel;
  if (XlabelIn.empty())
    Xlabel.assign("Frame");
  else
    Xlabel = XlabelIn;
  Dimension Xdim;
  // First determine if X values increase monotonically with a regular step
  bool isMonotonic = true;
  double xstep = 1.0;
  if (Xvals.size() > 1) {
    xstep = (Xvals.back() - Xvals.front()) / (double)(Xvals.size() - 1);
    for (Darray::const_iterator X = Xvals.begin()+2; X != Xvals.end(); ++X)
      if ((*X - *(X-1)) - xstep > Constants::SMALL) {
        isMonotonic = false;
        break;
      }
    // Set dim even for non-monotonic sets so Label is correct. FIXME is this ok?
    Xdim = Dimension( Xvals.front(), xstep, Xlabel );
  } else
    // No X values. set generic X dim.
    Xdim = Dimension(1.0, 1.0, Xlabel);
  if (debug_ > 0) {
    mprintf("DEBUG: xstep %g xmin %g\n", Xdim.Step(), Xdim.Min());
    if (isMonotonic) mprintf("DEBUG: Xdim is monotonic.\n");
  }
  for (const_iterator ds = Sets.begin(); ds != Sets.end(); ++ds) {
    if (*ds == 0) continue; // TODO: Warn about blanks?
    if (debug_ > 0) mprintf("DEBUG: AddOrAppend set '%s'", (*ds)->legend());
    if (isMonotonic) (*ds)->SetDim(Dimension::X, Xdim);
    DataSet* existingSet = CheckForSet( (*ds)->Meta() );
    if (existingSet == 0) {
      // New set. If set is scalar 1D but X values are not monotonic,
      // convert to XY mesh if necessary.
      if ( !isMonotonic &&
           (*ds)->Group() == DataSet::SCALAR_1D &&
           (*ds)->Type() != DataSet::XYMESH )
      {
        DataSet* xyptr = AddSet( DataSet::XYMESH, (*ds)->Meta() );
        if (xyptr == 0) {
          mprinterr("Error: Could not convert set %s to XY mesh.\n", (*ds)->legend());
          continue; // TODO exit instead?
        }
        if ( (*ds)->Size() != Xvals.size() ) { // Sanity check
          mprinterr("Error: # of X values does not match set %s size.\n", (*ds)->legend());
          continue;
        }
        DataSet_1D const& set = static_cast<DataSet_1D const&>( *(*ds) );
        DataSet_Mesh& xy = static_cast<DataSet_Mesh&>( *xyptr );
        for (unsigned int i = 0; i != set.Size(); i++)
          xy.AddXY( Xvals[i], set.Dval(i) );
        xy.SetDim(Dimension::X, Xdim);
        if (debug_ > 0) mprintf(", New set, converted to XY-MESH\n");
        // Free memory since set has now been converted.
        delete *ds;
      } else { // No conversion. Just add.
        (*ds)->SetDim(Dimension::X, Xdim);
        AddSet( *ds );
        if (debug_ > 0) mprintf(", New set\n");
      }
    } else {
      if (debug_ > 0) mprintf(", appending to existing set\n");
      // Set exists. Try to append this set to existing set.
      bool canAppend = true;
      if ( (*ds)->Group() == DataSet::GENERIC ) {
        // For GENERIC sets, base Type must match. // TODO: Should this logic be in DataSets?
        if ( (*ds)->Type() != existingSet->Type() )
          canAppend = false;
      } else {
        // For non-GENERIC sets, Group must match
        if ( (*ds)->Group() != existingSet->Group() )
          canAppend = false;
      }
      if (!canAppend)
        mprinterr("Error: Cannot append set of type %s to set of type %s\n",
                  DataArray[(*ds)->Type()].Description,
                  DataArray[existingSet->Type()].Description);
      // If cannot append or attempt to append fails, rename and add as new set.
      if (!canAppend || existingSet->Append( *ds )) { // TODO Dimension check?
        if (canAppend)
          mprintf("Warning: Append currently not supported for type %s\n",
                  DataArray[existingSet->Type()].Description);
        MetaData md = (*ds)->Meta();
        md.SetName( GenerateDefaultName("X") );
        mprintf("Warning: Renaming %s to %s\n", (*ds)->Meta().PrintName().c_str(),
                md.PrintName().c_str());
        (*ds)->SetMeta( md );
       
        AddSet( *ds );
      } else // Set was appended to existing set; memory can be freed.
        delete *ds;
    }
  } // END loop over input sets
  return 0;
}
Ejemplo n.º 13
0
//  Exec_SortEnsembleData::Sort_pH_Data()
int Exec_SortEnsembleData::Sort_pH_Data(DataSetList const& setsToSort, DataSetList& OutputSets,
                                        unsigned int maxFrames)
const
{
  // Cast sets back to DataSet_PHREMD
  typedef std::vector<DataSet_PHREMD*> Parray;
  Parray PHsets;
  for (DataSetList::const_iterator ds = setsToSort.begin(); ds != setsToSort.end(); ++ds)
    PHsets.push_back( (DataSet_PHREMD*)*ds );

  // Gather initial pH data values, ensure no duplicates
  typedef std::vector<double> Darray;
  Darray pHvalues;
# ifdef MPI
  pHvalues.resize( Parallel::Ensemble_Size() );
  Darray phtmp;
  for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds)
    phtmp.push_back( (*ds)->Initial_pH() );
  if (comm_.AllGather(&phtmp[0], phtmp.size(), MPI_DOUBLE, &pHvalues[0])) {
    rprinterr("Error: Gathering pH values.\n");
    return 1;
  }
# else
  for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds)
    pHvalues.push_back( (*ds)->Initial_pH() );
# endif
  ReplicaInfo::Map<double> pH_map;
  if (pH_map.CreateMap( pHvalues )) {
    rprinterr("Error: Duplicate pH value detected (%.2f) in ensemble.\n", pH_map.Duplicate());
    return 1;
  }
  Darray sortedPH;
  mprintf("\tInitial pH values:");
  for (ReplicaInfo::Map<double>::const_iterator ph = pH_map.begin(); ph != pH_map.end(); ++ph)
  {
    mprintf(" %6.2f", ph->first);
    sortedPH.push_back( ph->first );
  }
  mprintf("\n");

  // Create sets to hold sorted pH values. Create a set for each pH value
  // and each residue. Final output sets will be PH0R0, PH0R1, PH1R0, ...
  // TODO check that residue info all the same
  DataSet_PHREMD::Rarray const& Residues = PHsets[0]->Residues();
  int defaultState = 0;
# ifdef MPI
  if ( PHsets[0]->Type() == DataSet::PH_IMPL)
    defaultState = -1;
# endif
  if (debug_ > 0)
    rprintf("DEBUG: Sorting %u frames for %zu sets, %zu pH values.\n",
            maxFrames, PHsets.size(), sortedPH.size());
  for (unsigned int idx = 0; idx != sortedPH.size(); idx++) {
    OutputSets.SetEnsembleNum( idx );
    for (unsigned int res = 0; res != Residues.size(); ++res) {
      MetaData md(PHsets[0]->Meta().Name(), Residues[res].Name().Truncated(), Residues[res].Num());
      DataSet_pH* out = (DataSet_pH*)OutputSets.AddSet( DataSet::PH, md );
      if (out==0) return 1;
      //out->SetLegend( "pH " + doubleToString( sortedPH[idx] ) );
      out->Set_Solvent_pH( sortedPH[idx] );
      out->SetResidueInfo( Residues[res] );
      out->SetTimeValues(PHsets[0]->Time());
      out->Resize( maxFrames, defaultState );
    }
  }

  // ---------------------------------------------
  if ( PHsets[0]->Type() == DataSet::PH_EXPL) {
    // Loop over unsorted sets
    for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds)
    {
      DataSet_PHREMD_Explicit* in = (DataSet_PHREMD_Explicit*)*ds;
      unsigned int phidx = 0;
      for (unsigned int n = 0; n < maxFrames; n++)
      {
        float phval = in->pH_Values()[n];
        int setidx = pH_map.FindIndex( phval ) * Residues.size();
        //rprintf("DEBUG: %6u Set %10s pH= %6.2f going to %2i\n", n+1, in->legend(), phval, idx);
        //mflush();
        for (unsigned int res = 0; res < in->Residues().size(); res++, setidx++, phidx++)
        {
          DataSet_pH* out = (DataSet_pH*)OutputSets[setidx];
          //if (res == 0 && idx == 0) {
          //  rprintf("DEBUG: Frame %3u res %2u State %2i pH %6.2f\n", 
          //          n, res, in->Res(res).State(n), phval);
          //  mflush();
          //}
          out->SetState(n, in->ResStates()[phidx], in->RecordType(n));
        }
      }
    } // END loop over unsorted sets
#   ifdef MPI
    // Now we need to reduce down each set onto the thread where it belongs.
    if (Parallel::World().Size() > 1) {
      for (int idx = 0; idx != (int)OutputSets.size(); idx++) {
        DataSet_pH* out = (DataSet_pH*)OutputSets[idx];
        int ensembleRank = Parallel::MemberEnsCommRank( out->Meta().EnsembleNum() );
        //rprintf("DEBUG: Reduce set %s to rank %i\n", out->legend(), ensembleRank);
        out->Reduce( comm_, ensembleRank );
      }
      // Remove sets that do not belong on this rank
      for (int idx = (int)OutputSets.size() - 1; idx > -1; idx--) {
        DataSet* out = OutputSets[idx];
        int ensembleRank = Parallel::MemberEnsCommRank( out->Meta().EnsembleNum() );
        if (ensembleRank != comm_.Rank()) {
          //rprintf("DEBUG: Remove set %s (%i) from rank %i\n", out->legend(),
          //        idx, comm_.Rank());
          OutputSets.RemoveSet( out );
        }
      }
    }
#   endif
  // ---------------------------------------------
  } else if ( PHsets[0]->Type() == DataSet::PH_IMPL) {
#   ifdef MPI
    typedef std::vector<int> Iarray;
    typedef std::vector<Iarray> Iarray2;
    typedef std::vector<bool> Barray;
    // True if I have this pH value
    Barray isMyPh( sortedPH.size(), false );
    // Which rank in ensemble has which pH
    Iarray pHrank( sortedPH.size(), 0 );
    for (int phidx = 0; phidx != (int)sortedPH.size(); phidx++)
    {
      int ensembleRank = Parallel::MemberEnsCommRank( phidx );
      pHrank[phidx] = ensembleRank;
      isMyPh[phidx] = (ensembleRank == comm_.Rank());
    }
    // DEBUG
    for (unsigned int idx = 0; idx != pHrank.size(); idx++)
      mprintf("\tpH %6.2f on rank %i\n", sortedPH[idx], pHrank[idx]);
    // Hold frame-residue-state for each pH not on this rank.
    Iarray2 FrmResState( sortedPH.size() );
    // Loop over unsorted sets
    for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds)
    {
      DataSet_PHREMD_Implicit* in = (DataSet_PHREMD_Implicit*)*ds;
      // Loop over frames
      for (unsigned int n = 0; n < maxFrames; n++)
      {
        DataSet_PHREMD_Implicit::Record const& Rec = in->Records()[n];
        float phval = Rec.pH();
        int phidx = pH_map.FindIndex( phval );
        if (isMyPh[phidx]) {
          // This pH belongs to me. Set value.
          int setidx = phidx * Residues.size();
          if (Rec.RecType() == Cph::FULL_RECORD) {
            // Info for all residues
            for (unsigned int res = 0; res < in->Residues().size(); res++, setidx++)
              ((DataSet_pH*)OutputSets[setidx])->SetState(n, Rec.ResStates()[res], Rec.RecType());
          } else if (Rec.RecType() > -1) {
            // Info for single residue, record type for all residues
            //rprintf("\tSetting my pH %6.2f frame %8i state %2i idx %6i res %6i '%s'\n", sortedPH[phidx], n, Rec.ResStates()[0], setidx, Rec.RecType(), OutputSets[setidx+Rec.RecType()]->legend());
            for (int res = 0; res < (int)in->Residues().size(); res++, setidx++)
              if (res == Rec.RecType())
                ((DataSet_pH*)OutputSets[setidx])->SetState(n, Rec.ResStates()[0], Rec.RecType());
              else
                ((DataSet_pH*)OutputSets[setidx])->SetRecType(n, Rec.RecType());
          }
        } else {
          // This pH belongs to another rank. Save it.
          if (Rec.RecType() > -1) {
            // Info for a single residue present
            FrmResState[phidx].push_back( n );
            FrmResState[phidx].push_back( Rec.RecType() );
            FrmResState[phidx].push_back( Rec.ResStates()[0] );
          } else {
            // Info for all residues present
            FrmResState[phidx].push_back( n );
            FrmResState[phidx].push_back( Rec.RecType() );
            for (unsigned int res = 0; res < in->Residues().size(); res++)
              FrmResState[phidx].push_back( Rec.ResStates()[res] );
          }
        }
      } // END loop over frames
    } // END loop over sets
    // DEBUG
/*
    comm_.Barrier();
    for (int rank = 0; rank < comm_.Size(); rank++)
    {
      if (rank == comm_.Rank())
      {
        for (unsigned int phidx = 0; phidx != sortedPH.size(); phidx++) {
          rprintf("DEBUG: pH %6.2f: %8s %6s %2s\n", sortedPH[phidx], "Frm", "Res", "St");
          Iarray const& FRS = FrmResState[phidx];
          unsigned int idx = 0;
          while (idx < FRS.size()) {
            int rec = FRS[idx+1];
            if (rec > -1) {
              rprintf("                  %8i %6i %2i\n", FRS[idx], rec, FRS[idx+2]);
              idx += 3;
            } else {
              rprintf("                  %8i %6i All Residues\n", FRS[idx], rec);
              idx += (2 + Residues.size());
            }
          }
        }
      }
      comm_.Barrier();
    }
*/
    // Communicate states to other ranks
    typedef std::vector<unsigned int> Uarray;
    Uarray sizeOnRank( comm_.Size() );
    for (unsigned int phidx = 0; phidx != sortedPH.size(); phidx++)
    {
      // Each rank says how many frames of this pH they have collected and
      // send to rank the pH belongs to.
      unsigned int nph = FrmResState[phidx].size();
      comm_.Gather(&nph, 1, MPI_UNSIGNED, &sizeOnRank[0], pHrank[phidx]);
      if (pHrank[phidx] == comm_.Rank())
      {
        // This pH belongs to me. I should have no frames at this pH.
        if (sizeOnRank[comm_.Rank()] > 0) {
          rprinterr("Internal Error: Rank has frames to communicate at its pH\n");
          Parallel::Abort(1);
        }
        unsigned int totalSize = 0;
        for (unsigned int idx = 0; idx != sizeOnRank.size(); idx++) {
          totalSize += sizeOnRank[idx];
          //rprintf("DEBUG: Rank %4u has %8u frames of pH %6.2f\n",
          //        idx, sizeOnRank[idx], sortedPH[phidx]);
        }
        //rprintf("DEBUG: Total incoming size: %u\n", totalSize);
        FrmResState[phidx].resize( totalSize );
        // Receive state info for this pH from other ranks
        int* frsArray = &(FrmResState[phidx][0]);
        for (int rank = 0; rank != comm_.Size(); rank++) {
          if (rank != comm_.Rank()) {
            comm_.Recv(frsArray, sizeOnRank[rank], MPI_INT, rank, 1600+rank);
            frsArray += sizeOnRank[rank];
          }
        }
      } else {
        // This pH belongs to another rank. Send my info there.
        int* frsArray = &(FrmResState[phidx][0]);
        comm_.Send(frsArray, nph, MPI_INT, pHrank[phidx], 1600+comm_.Rank());
      }
      comm_.Barrier();
    }
    // Fill in state info
    std::vector<DataSet*> ToRemove;
    for (unsigned int phidx = 0; phidx != sortedPH.size(); phidx++)
    {
      int setidx = phidx * Residues.size();
      if (pHrank[phidx] == comm_.Rank())
      {
        Iarray const& FRS = FrmResState[phidx];
        // This pH belongs to me. Fill in the information received from
        // other ranks.
        unsigned int idx = 0;
        while (idx < FRS.size()) {
          int rec = FRS[idx+1];
          if (rec > -1) {
            // Info for single residue, record type for all residues
            //rprintf("\tSetting pH %6.2f frame %8i state %2i idx %6i res %6i '%s'\n", sortedPH[phidx], FRS[idx], FRS[idx+2], setidx, rec, OutputSets[setidx+rec]->legend());
            for (int res = 0; res != (int)Residues.size(); res++) {
              DataSet_pH* out = (DataSet_pH*)OutputSets[setidx + res];
              if (rec == res)
                out->SetState( FRS[idx], FRS[idx+2], rec );
              else
                out->SetRecType( FRS[idx], rec );
            }
            idx += 3;
          } else {
            //rprintf("                  %8i %6i All Residues\n", FRS[idx], rec);
            int frm = FRS[idx];
            idx += 2;
            for (unsigned int res = 0; res != Residues.size(); res++, idx++) {
              DataSet_pH* out = (DataSet_pH*)OutputSets[setidx + res];
              out->SetState( frm, FRS[idx], rec );
            }
          }
        }
        // Fill in any remaining data. FIXME safe to assume first frame is set?
        for (unsigned int res = 0; res != Residues.size(); res++) {
          DataSet_pH* out = (DataSet_pH*)OutputSets[setidx + res];
          for (unsigned int n = 1; n < maxFrames; n++)
            if (out->State(n) == -1)
              out->SetState(n, out->State(n-1), out->RecordType(n));
        }
      } else {
        // This pH does not belong to me. Mark associated data sets to be removed.
        for (unsigned int res = 0; res != Residues.size(); res++)
          ToRemove.push_back( OutputSets[setidx + res] );
      }
    }
    // Remove data sets that do not belong to me.
    for (std::vector<DataSet*>::reverse_iterator it = ToRemove.rbegin();
                                                 it != ToRemove.rend(); ++it)
    {
      //rprintf("DEBUG: '%s' does not belong to me.\n", (*it)->legend());
      OutputSets.RemoveSet( *it );
    }
#   else /* if not MPI */
    // Loop over frames
    for (unsigned int n = 0; n < maxFrames; n++)
    {
      // Loop over unsorted sets
      for (Parray::const_iterator ds = PHsets.begin(); ds != PHsets.end(); ++ds)
      {
        DataSet_PHREMD_Implicit* in = (DataSet_PHREMD_Implicit*)*ds;
        DataSet_PHREMD_Implicit::Record const& Rec = in->Records()[n];
        float phval = Rec.pH();
        int setidx = pH_map.FindIndex( phval ) * Residues.size();
        if (Rec.RecType() == Cph::FULL_RECORD) {
          for (unsigned int res = 0; res < in->Residues().size(); res++, setidx++)
          {
            DataSet_pH* out = (DataSet_pH*)OutputSets[setidx];
            //if (res == 0 && idx == 0) {
            //  rprintf("DEBUG: Frame %3u res %2u State %2i pH %6.2f\n", 
            //          n, res, in->Res(res).State(n), phval);
            //  mflush();
            //}
            out->SetState(n, Rec.ResStates()[res], Rec.RecType());
          }
        } else {
          for (int res = 0; res < (int)in->Residues().size(); res++, setidx++)
          {
            DataSet_pH* out = (DataSet_pH*)OutputSets[setidx];
            if (res == Rec.RecType())
              out->SetState(n, Rec.ResStates()[0], Rec.RecType());
            else
              // State for this residue not recorded - use previous state.
              // Should be fine since first state always has all residues.
              out->SetState(n, out->State(n-1), Rec.RecType());
          }
        }
      } // END loop over unsorted sets
    } // END loop over frames
#   endif /* MPI */
  // ---------------------------------------------
  } else {
    return 1; // Sanity check
  }
  return 0;
}
Ejemplo n.º 14
0
// Analysis_Wavelet::Analyze()
Analysis::RetType Analysis_Wavelet::Analyze() {
    // Step 1 - Create a matrix that is #atoms rows by #frames - 1 cols,
    //          where matrix(frame, atom) is the distance that atom has
    //          travelled from the previous frame.
    // TODO: Implement this in Action_Matrix()?
    mprintf("    WAVELET:\n");
    // First set up atom mask.
    if (coords_->Top().SetupIntegerMask( mask_ )) return Analysis::ERR;
    mask_.MaskInfo();
    int natoms = mask_.Nselected();
    int nframes = (int)coords_->Size();
    if (natoms < 1 || nframes < 2) {
        mprinterr("Error: Not enough frames (%i) or atoms (%i) in '%s'\n",
                  nframes, natoms, coords_->legend());
        return Analysis::ERR;
    }
    Matrix<double> d_matrix;
    mprintf("\t%i frames, %i atoms, distance matrix will require %.2f MB\n",
            (double)d_matrix.sizeInBytes(nframes, natoms) / (1024.0*1024.0));
    d_matrix.resize(nframes, natoms);
    // Get initial frame.
    Frame currentFrame, lastFrame;
    currentFrame.SetupFrameFromMask( mask_, coords_->Top().Atoms() );
    lastFrame = currentFrame;
    coords_->GetFrame( 0, lastFrame, mask_ );
    // Iterate over frames
    for (int frm = 1; frm != nframes; frm++) {
        coords_->GetFrame( frm, currentFrame, mask_ );
        int idx = frm; // Position in distance matrix; start at column 'frame'
        for (int at = 0; at != natoms; at++, idx += nframes)
            // Distance of atom in currentFrame from its position in lastFrame.
            d_matrix[idx] = sqrt(DIST2_NoImage( currentFrame.XYZ(at), lastFrame.XYZ(at) ));
        //lastFrame = currentFrame; // TODO: Re-enable?
    }
# ifdef DEBUG_WAVELET
    // DEBUG: Write matrix to file.
    CpptrajFile dmatrixOut; // DEBUG
    dmatrixOut.OpenWrite("dmatrix.dat");
    Matrix<double>::iterator mval = d_matrix.begin();
    for (int row = 0; row != natoms; row++) {
        for (int col = 0; col != nframes; col++)
            dmatrixOut.Printf("%g ", *(mval++));
        dmatrixOut.Printf("\n");
    }
    dmatrixOut.CloseFile();
# endif

    // Precompute some factors for calculating scaled wavelets.
    const double one_over_sqrt_N = 1.0 / sqrt(static_cast<double>( nframes ));
    std::vector<int> arrayK( nframes );
    arrayK[0] = -1 * (nframes/2);
    for (int i = 1; i != nframes; i++)
        arrayK[i] = arrayK[i-1] + 1;
# ifdef DEBUG_WAVELET
    mprintf("DEBUG: K:");
    for (std::vector<int>::const_iterator kval = arrayK.begin(); kval != arrayK.end(); ++kval)
        mprintf(" %i", *kval);
    mprintf("\n");
# endif

    // Step 2 - Get FFT of wavelet for each scale.
    PubFFT pubfft;
    pubfft.SetupFFTforN( nframes );
    mprintf("\tMemory required for scaled wavelet array: %.2f MB\n",
            (double)(2 * nframes * nb_ * sizeof(double)) / (1024 * 1024));
    typedef std::vector<ComplexArray> WaveletArray;
    WaveletArray FFT_of_Scaled_Wavelets;
    FFT_of_Scaled_Wavelets.reserve( nb_ );
    typedef std::vector<double> Darray;
    Darray scaleVector;
    scaleVector.reserve( nb_ );
    Darray MIN( nb_ * 2 );
    for (int iscale = 0; iscale != nb_; iscale++)
    {
        // Calculate and store scale factor.
        scaleVector.push_back( S0_ * pow(2.0, iscale * ds_) );
        // Populate MIN array
        MIN[iscale    ] = (0.00647*pow((correction_*scaleVector.back()),1.41344)+19.7527)*chival_;
        MIN[iscale+nb_] = correction_*scaleVector.back();
        // Calculate scalved wavelet
        ComplexArray scaledWavelet;
        switch (wavelet_type_) {
        case W_MORLET:
            scaledWavelet = F_Morlet(arrayK, scaleVector.back());
            break;
        case W_PAUL  :
            scaledWavelet = F_Paul(arrayK, scaleVector.back());
            break;
        case W_NONE  :
            return Analysis::ERR; // Sanity check
        }
#   ifdef DEBUG_WAVELET
        PrintComplex("wavelet_before_fft", scaledWavelet);
#   endif
        // Perform FFT
        pubfft.Forward( scaledWavelet );
        // Normalize
        scaledWavelet.Normalize( one_over_sqrt_N );
#   ifdef DEBUG_WAVELET
        PrintComplex("wavelet_after_fft", scaledWavelet);
#   endif
        FFT_of_Scaled_Wavelets.push_back( scaledWavelet );
    }
# ifdef DEBUG_WAVELET
    mprintf("DEBUG: Scaling factors:");
    for (Darray::const_iterator sval = scaleVector.begin(); sval != scaleVector.end(); ++sval)
        mprintf(" %g", *sval);
    mprintf("\n");
    mprintf("DEBUG: MIN:");
    for (int i = 0; i != nb_; i++)
        mprintf(" %g", MIN[i]);
    mprintf("\n");
# endif

    // Step 3 - For each atom, calculate the convolution of scaled wavelets
    //          with rows (atom distance vs frame) via dot product of the
    //          frequency domains, i.e. Fourier-transformed, followed by an
    //          inverse FT.
    DataSet_MatrixFlt& OUT = static_cast<DataSet_MatrixFlt&>( *output_ );
    mprintf("\tMemory required for output matrix: %.2f MB\n",
            (double)Matrix<float>::sizeInBytes(nframes, natoms)/(1024.0*1024.0));
    OUT.Allocate2D( nframes, natoms ); // Should initialize to zero
    Matrix<double> MAX;
    mprintf("\tMemory required for Max array: %.2f MB\n",
            (double)MAX.sizeInBytes(nframes, natoms)/(1024.0*1024.0));
    MAX.resize( nframes, natoms );
    Darray magnitude( nframes ); // Scratch space for calculating magnitude across rows
    for (int at = 0; at != natoms; at++) {
        ComplexArray AtomSignal( nframes ); // Initializes to zero
        // Calculate the distance variance for this atom and populate the array.
        int midx = at * nframes; // Index into d_matrix
        int cidx = 0;            // Index into AtomSignal
        double d_avg = 0.0;
        double d_var = 0.0;
        for (int frm = 0; frm != nframes; frm++, cidx += 2, midx++) {
            d_avg += d_matrix[midx];
            d_var += (d_matrix[midx] * d_matrix[midx]);
            AtomSignal[cidx] = d_matrix[midx];
        }
        d_var = (d_var - ((d_avg * d_avg) / (double)nframes)) / ((double)(nframes - 1));
#   ifdef DEBUG_WAVELET
        mprintf("VARIANCE: %g\n", d_var);
#   endif
        double var_norm = 1.0 / d_var;
        // Calculate FT of atom signal
        pubfft.Forward( AtomSignal );
#   ifdef DEBUG_WAVELET
        PrintComplex("AtomSignal", AtomSignal);
#   endif
        // Normalize
        AtomSignal.Normalize( one_over_sqrt_N );
        // Calculate dot product of atom signal with each scaled FT wavelet
        for (int iscale = 0; iscale != nb_; iscale++) {
            ComplexArray dot = AtomSignal.TimesComplexConj( FFT_of_Scaled_Wavelets[iscale] );
            // Inverse FT of dot product
            pubfft.Back( dot );
#     ifdef DEBUG_WAVELET
            PrintComplex("InverseFT_Dot", dot);
#     endif
            // Chi-squared testing
            midx = at * nframes;
            cidx = 0;
            for (int frm = 0; frm != nframes; frm++, cidx += 2, midx++) {
                magnitude[frm] = (dot[cidx]*dot[cidx] + dot[cidx+1]*dot[cidx+1]) * var_norm;
                if (magnitude[frm] < MIN[iscale])
                    magnitude[frm] = 0.0;
                if (magnitude[frm] > MAX[midx]) {
                    MAX[midx] = magnitude[frm];
                    //Indices[midx] = iscale
                    OUT[midx] = (float)(correction_ * scaleVector[iscale]);
                }
            }
#     ifdef DEBUG_WAVELET
            mprintf("DEBUG: AbsoluteValue:");
            for (Darray::const_iterator dval = magnitude.begin(); dval != magnitude.end(); ++dval)
                mprintf(" %g", *dval);
            mprintf("\n");
#     endif
        } // END loop over scales
    } // END loop over atoms
# ifdef DEBUG_WAVELET
    // DEBUG: Print MAX
    CpptrajFile maxmatrixOut; // DEBUG
    maxmatrixOut.OpenWrite("maxmatrix.dat");
    for (int col = 0; col != nframes; col++) {
        for (int row = 0; row != natoms; row++)
            maxmatrixOut.Printf("%g ", MAX.element(col, row));
        maxmatrixOut.Printf("\n");
    }
    maxmatrixOut.CloseFile();
# endif

    return Analysis::OK;
}
Ejemplo n.º 15
0
/** Perform curve fitting via Levenberg-Marquardt method with optional bounds.
  * \param fxnIn Function to fit.
  * \param Xvals_ target X values (ordinates, M)
  * \param Yvals_ target Y values (coordinates, M)
  * \param ParamVec input parameters(N); at finish contains best esimate of fit parameters
  * \param boundsIn true if parameter has bounds (N)
  * \param lboundIn contain lower bounds for parameter (N)
  * \param uboundIn contain upper bounds for parameter (N)
  * \param weightsIn contain weights for Y values (M)
  * \param tolerance Fit tolerance
  * \param maxIterations Number of iterations to try.
  */
int CurveFit::LevenbergMarquardt(FitFunctionType fxnIn, Darray const& Xvals_,
                                 Darray const& Yvals_, Darray& ParamVec,
                                 std::vector<bool> const& boundsIn,
                                 Darray const& lboundIn, Darray const& uboundIn,
                                 Darray const& weightsIn,
                                 double tolerance, int maxIterations)
{
  int info = 0;
  hasBounds_ = boundsIn;
  Ubound_ = uboundIn;
  Lbound_ = lboundIn;
  Weights_ = weightsIn;
  if (ParametersHaveProblems(Xvals_, Yvals_, ParamVec)) {
    DBGPRINT("Error: %s\n", errorMessage_);
    return info;
  }
  // Set initial parameters
  finalY_ = Yvals_;
  Params_= ParamVec;  // Internal parameter vector
  fParms_ = ParamVec; // Parameters for function evaluation
  Pvec_to_Params( ParamVec );

  fxn_ = fxnIn;
  m_ = Xvals_.size();        // Number of values (rows)
  n_ = Params_.size();       // Number of parameters (cols)
  Darray residual_( m_ );    // Contain Y vals at current Params minus original Y
  // Jacobian matrix/R: m rows by n cols, transposed.
  jacobian_.assign( m_ * n_, 0.0 );

  // For holding diagonal elements for scaling // TODO: Rename
  Darray diag( n_, 0.0 );
  // Workspace arrays
  Darray work1( n_, 0.0 );
  Darray work2( n_, 0.0 );
  Darray newResidual( m_, 0.0 );
  // delta specifies an upper bound on the euclidean norm of d*x
  double delta = 0.0;
  // factor is positive input variable used in determining the initial step
  // bound. This bound is set to the product of factor and the euclidean norm
  // of diag*x if nonzero, or else to factor itself. In most cases factor should
  // lie in the interval (.1,100.). 100. is a generally recommended value.
  // TODO: Make input parameter
  const double factor = 100.0;
  // gtol is a nonnegative input variable. Termination occurs when the cosine 
  // of the angle between residual and any column of the Jacobian is at most 
  // gtol in absolute value. Therefore, gtol measures the orthogonality
  // desired between the function vector and the columns of the Jacobian.
  // TODO: Make input parameter
  const double gtol = 0.0;
  // Smallest possible magnitude
  // TODO: Make Constant?
  const double dwarf = DBL_MIN;
  // Levenberg-Marquard parameter
  double LM_par = 0.0;
  //  xtol is a nonnegative input variable. Termination occurs when the 
  //  relative error between two consecutive iterates is at most xtol.
  //  Therefore, xtol measures the relative error desired in the 
  //  approximate solution.
  // TODO: Make input paramter
  double xtol = 0.0;
  // maxfev is the maxiumum number of allowed function evaluations.
  // NOTE: Included here for complete compatibility with eariler code,
  //       though may not be strictly necessary.
  dsize maxfev = (n_ + 1) * (dsize)maxIterations;

  // Evaluate initial function, obtain residual
  EvaluateFxn( Xvals_, Yvals_, Params_, residual_ );

  // Calculate norm of the residual
  double rnorm = VecNorm( residual_ );
  DBGPRINT("Rnorm= %g\n", rnorm);

  dsize nfev = 1; // Will be set to calls to fxn_. 1 already.

  // MAIN LOOP
  int currentIt = 0;
  while ( currentIt < maxIterations ) {
    DBGPRINT("DEBUG: ----- Iteration %i ------------------------------\n", currentIt+1);
    // Calculate the Jacobian using the forward-difference approximation.
    CalcJacobian_ForwardDiff( Xvals_, Yvals_, Params_, residual_, newResidual );
    PrintMatrix( "Jacobian", n_, m_, jacobian_ );
    nfev += n_;

    // -------------------------------------------
    // | BEGIN QRFAC
    // -------------------------------------------
    // Perform QR factorization of Jacobian via Householder transformations
    // with column pivoting:
    //   J * P = Q * R
    // where J is the Jacobian, P is the permutation matrix, Q is an orthogonal
    // matrix, and R is an upper trapezoidal matrix with diagonal elements of
    // nonincreasing magnitude. The Householder transformation for column k,
    // k = 1,2,...,min(m,n), is of the form:
    //   I = (1/u[k])*u*ut
    // where u has zeros in the first k-1 positions. Adapted from routine qrfac_
    // in Grace 5.1.22 lmdif.c, which in turn is derived from an earlier linpack
    // subroutine.
    DBGPRINT("\nQRFAC ITERATION %i\n", currentIt+1);
    // Rdiag will hold the diagonal elements of R.
    Darray Rdiag(n_, 0.0);
    // Jpvt defines the permutation matrix p such that a*p = q*r. Column j of p
    // is column Jpvt[j] of the identity matrix.
    Iarray Jpvt(n_, 0.0);
    // JcolNorm Will hold the norms of the columns of input Jacobian.
    Darray JcolNorm_(n_, 0.0);
    // Compute the initial column norms and initialize arrays.
    for (dsize in = 0; in != n_; in++) {
      JcolNorm_[in] = VecNorm( jacobian_.begin() + (in * m_), m_ ); 
      Rdiag[in] = JcolNorm_[in];
      work1[in] = Rdiag[in];
      Jpvt[in] = in;
      DBGPRINT("%lu: Rdiag= %12.6g    wa= %12.6g    ipvt= %i\n",
             in+1, Rdiag[in], work1[in], Jpvt[in]+1);
    }

    // Reduce Jacobian to R with Householder transformations.
    dsize min_m_n = std::min( m_, n_ );
    for (dsize in = 0; in != min_m_n; in++) {
      // Bring the column of largest norm into the pivot position.
      dsize kmax = in;
      for (dsize k = in; k != n_; k++) {
        DBGPRINT("\tRdiag[%lu]= %g    Rdiag[%lu]= %g\n", k+1, Rdiag[k], kmax+1, Rdiag[kmax]);
        if (Rdiag[k] > Rdiag[kmax])
          kmax = k;
      }
      DBGPRINT("Elt= %lu    Kmax= %lu\n", in+1, kmax+1);
      if (kmax != in) {
        for (dsize i = 0; i != m_; i++) {
          double temp = jacobian_[i + in * m_];
          jacobian_[i + in   * m_] = jacobian_[i + kmax * m_];
          jacobian_[i + kmax * m_] = temp;
          DBGPRINT("DBG: Swap jac[%lu,%lu] with jac[%lu,%lu]\n", i+1, in+1, i+1, kmax+1);
        }
        Rdiag[kmax] = Rdiag[in];
        work1[kmax] = work1[in];
        dsize k = Jpvt[in];
        Jpvt[in] = Jpvt[kmax];
        Jpvt[kmax] = k;
      }

      // Compute the Householder transformation to reduce the j-th column
      // of Jacobian to a multiple of the j-th unit vector.
      double ajnorm = VecNorm( jacobian_.begin() + (in + in * m_), m_ - in );
      DBGPRINT("#Elt= %lu    mat[%lu]= %g    ajnorm= %g\n",
             m_ - in, in + in * m_, jacobian_[in + in * m_], ajnorm);
      if (ajnorm != 0.0) {
        if (jacobian_[in + in * m_] < 0.0)
          ajnorm = -ajnorm;
        for (dsize im = in; im < m_; im++)
          jacobian_[im + in * m_] /= ajnorm;
        jacobian_[in + in * m_] += 1.0;

        // Apply the transfomation to the remaining columns and update the norms
        dsize in1 = in + 1;
        if (in1 < n_) {
          for (dsize k = in1; k < n_; k++) {
            double sum = 0.0;
            for (dsize i = in; i < m_; i++)
              sum += jacobian_[i + in * m_] * jacobian_[i + k * m_];
            double temp = sum / jacobian_[in + in * m_];
            for (dsize i = in; i < m_; i++)
              jacobian_[i + k * m_] -= temp * jacobian_[i + in * m_];
            if (Rdiag[k] != 0.0) {
              temp = jacobian_[in + k * m_] / Rdiag[k];
              Rdiag[k] *= sqrt( std::max( 0.0, 1.0 - temp * temp ) );
              temp = Rdiag[k] / work1[k];
              DBGPRINT("\t\tQRFAC TEST: 0.5 * %g^2 <= %g\n", temp, machine_epsilon);
              if (0.05 * (temp * temp) <= machine_epsilon) {
                DBGPRINT("\t\tTEST PASSED\n");
                Rdiag[k] = VecNorm( jacobian_.begin() + (in1 + k * m_), m_ - in - 1 );
                work1[k] = Rdiag[k];
              }
            }
            DBGPRINT("QRFAC Rdiag[%lu]= %g\n", k+1, Rdiag[k]);
          }
        }
      }
      Rdiag[in] = -ajnorm;
    }      
    // -------------------------------------------
    // | END QRFAC
    // -------------------------------------------

    PrintMatrix("QR", n_, m_, jacobian_);
    for (dsize in = 0; in != n_; in++)
      DBGPRINT("\tRdiag[%lu]= %12.6g    acnorm[%lu]= %12.6g    ipvt[%lu]= %i\n",
             in+1, Rdiag[in], in+1, JcolNorm_[in], in+1, Jpvt[in]+1);

    double xnorm = 0.0;
    if ( currentIt == 0 ) {
      // First iteration. Scale according to the norms of the columns of
      // the initial Jacobian.
      for (dsize in = 0; in != n_; in++) {
        if ( JcolNorm_[in] == 0.0 )
          diag[in] = 1.0;
        else
          diag[in] = JcolNorm_[in];
      }
      PrintVector("diag", diag);
      // Calculate norm of scaled params and init step bound delta
      for (dsize in = 0; in != n_; in++)
        work1[in] = diag[in] * Params_[in];
      xnorm = VecNorm( work1 );
      delta = factor * xnorm;
      if (delta == 0.0)
        delta = factor;
      DBGPRINT("Delta= %g\n", delta);
    }

    // Form Qt * residual and store in Qt_r. Only first n components of
    // Qt*r are needed.
    Darray Qt_r( n_, 0.0 );
    newResidual = residual_;
    for (dsize in = 0; in != n_; in++) {
      double matElt = jacobian_[in + in * m_];
      DBGPRINT("DEBUG: Element %lu = %g\n", in+1, matElt);
      if (matElt != 0.0) {
        double sum = 0.0;
        for (dsize i = in; i < m_; i++)
          sum += jacobian_[i + in *  m_] * newResidual[i];
        double temp = -sum / matElt;
        for (dsize i = in; i < m_; i++)
          newResidual[i] += jacobian_[i + in * m_] * temp;
      }
      jacobian_[in + in * m_] = Rdiag[in]; 
      DBGPRINT("\tRdiag[%lu]= %g\n", in+1, jacobian_[in + in * m_]);
      Qt_r[in] = newResidual[in];
      DBGPRINT("DEBUG: qtf[%lu]= %g\n", in+1, Qt_r[in]);
    }

    // Compute the norm of the scaled gradient.
    double gnorm = 0.0;
    if ( rnorm > 0.0 ) {
      for (dsize in = 0; in != n_; in++) {
        int l = Jpvt[ in ];
        if (JcolNorm_[in] != 0.0) {
          double sum = 0.0;
          for (dsize i2 = 0; i2 <= in; i2++) {
            sum += jacobian_[i2 + in * m_] * (Qt_r[i2] / rnorm);
            DBGPRINT("DEBUG: jacobian[%lu, %lu]= %g\n", i2+1, in+1, jacobian_[i2 + in * m_]);
          }
          // Determine max
          double d1 = fabs( sum / JcolNorm_[l] );
          gnorm = std::max( gnorm, d1 );
        }
      }
    }
    DBGPRINT("gnorm= %g\n", gnorm);
    // Test for convergence of gradient norm.
    if (gnorm <= gtol) {
      DBGPRINT("Gradient norm %g is less than gtol %g, iteration %i\n",
             gnorm, gtol, currentIt+1);
      info = 4;
      break;
    }

    // Rescale if necessary
    for (dsize in = 0; in != n_; in++)
      diag[in] = std::max( diag[in], JcolNorm_[in] );
    PrintVector("RescaleDiag", diag);
    double Ratio = 0.0;
    while (Ratio < 0.0001) {
      // -----------------------------------------
      // | LMPAR BEGIN
      // -----------------------------------------
      // NOTE: Adapted from lmpar_ in lmdif.c from Grace 5.1.22
      DBGPRINT("\nLMPAR ITERATION %i\n", currentIt+1);
      // Determine the Levenberg-Marquardt parameter.
      Darray Xvec(n_, 0.0);  // Will contain solution to A*x=b, sqrt(par)*D*x=0
      // Compute and store in Xvec the Gauss-Newton direction.
      // If the Jacobian is rank-deficient, obtain a least-squares solution.
      dsize rank = n_;
      for (dsize in = 0; in != n_; in++) {
        work1[in] = Qt_r[in];
        DBGPRINT("jac[%lu,%lu]= %12.6g  rank= %4lu", in+1, in+1, jacobian_[in + in * m_], rank);
        if (jacobian_[in + in * m_] == 0.0 && rank == n_)
          rank = in;
        if (rank < n_)
          work1[in] = 0.0;
        DBGPRINT("   wa1= %12.6g\n", work1[in]);
      }
      DBGPRINT("Final rank= %lu\n", rank);
      // Subtract 1 from rank to use as an index.
      long int rm1 = rank - 1;
      if (rm1 >= 0) {
        for (long int k = 0; k <= rm1; k++) {
          long int in = rm1 - k;
          work1[in] /= jacobian_[in + in * (long int)m_];
          DBGPRINT("wa1[%li] /= %g\n", in+1, jacobian_[in + in * (long int)m_]);
          long int in1 = in - 1;
          if (in1 > -1) {
            double temp = work1[in];
            for (long int i = 0; i <= in1; i++) {
              work1[i] -= jacobian_[i + in * (long int)m_] * temp;
              DBGPRINT("  wa1[%li] -= %g\n", i+1, jacobian_[i + in * (long int)m_]);
            }
          }
        }
      }
      PrintVector("work1", work1);
      for (dsize in = 0; in != n_; in++)
        Xvec[ Jpvt[in] ] = work1[in];
  
      // Evaluate the function at the origin, and test for acceptance of
      // the Gauss-Newton direction.
      for (dsize in = 0; in != n_; in++) {
        DBGPRINT("work2[%lu] = %g * %g\n", in+1, diag[in], Xvec[in]);
        work2[in] = diag[in] * Xvec[in];
      }
      double dxnorm = VecNorm( work2 );
      DBGPRINT("dxnorm= %g\n", dxnorm);
      double fp = dxnorm - delta;
      // Initialize counter for searching for LM parameter
      int lmIterations = 0;
      if (fp > 0.1 * delta) {
        // If the Jacobian is not rank deficient, the Newton step provdes a lower
        // bound, parl, for the zero of the function. Otherwise set this bound to
        // zero
        double parl = 0.0;
        if ( rank >= n_ ) {
          for (dsize in = 0; in != n_; in++) {
            int idx = Jpvt[in];
            work1[in] = diag[idx] * (work2[idx] / dxnorm);
          }
          for (dsize in = 0; in != n_; in++) {
            double sum = 0.0;
            long int in1 = (long int)in - 1;
            if (in1 > -1) {
              for (long int i = 0; i <= in1; i++)
                sum += jacobian_[i + in * m_] * work1[i];
            }
            work1[in] = (work1[in] - sum) / jacobian_[in + in * m_];
          }
          double temp = VecNorm(work1);
          parl = fp / delta / temp / temp;
        }
        DBGPRINT("parl= %g\n",parl);
  
        // Calculate an upper bound, paru, for the zero of the function
        for (dsize in = 0; in != n_; in++) {
          double sum = 0.0;
          for (dsize i = 0; i <= in; i++)
            sum += jacobian_[i + in * m_] * Qt_r[i];
          work1[in] = sum / diag[ Jpvt[in] ];
          DBGPRINT("paru work1[%lu]= %g\n", in+1, work1[in]);
        }
        double w1norm = VecNorm( work1 );
        double paru = w1norm / delta;
        DBGPRINT("paru = %g = %g / %g\n", paru, w1norm, delta);
        if (paru == 0.0)
          paru = dwarf / std::min( delta, 0.1 );
        DBGPRINT("paru= %g\n", paru);
        
        // If the current L-M parameter lies outside of the interval (parl,paru),
        // set par to the closer endpoint.
        LM_par = std::max( LM_par, parl );
        LM_par = std::min( LM_par, paru );
        if (LM_par == 0.0)
          LM_par = w1norm / dxnorm;
  
        // Iteration start.
        bool lmLoop = true;
        while (lmLoop) {
          ++lmIterations;
          DBGPRINT("\t[ lmLoop %i  parl= %g  paru= %g   LM_par= %g ]\n",
                 lmIterations, parl, paru, LM_par);
          // Evaluate the function at the current value of LM_par
          if (LM_par == 0.0)
            LM_par = std::max( dwarf, 0.001 * paru );
          double temp = sqrt( LM_par );
          for (dsize in = 0; in != n_; in++) {
            work1[in] = temp * diag[in];
            DBGPRINT("\tLMPAR work1[%lu]= %g = %g * %g\n", in+1, work1[in], temp, diag[in]);
          }
  
          // -----------------------------------------------
          // | BEGIN QRSOLV
          // -----------------------------------------------
          // NOTE: Adapted from qrsolv_ in lmdif.c from Grace 5.1.22 
          DBGPRINT("\nQRSOLV ITERATION %i\n", lmIterations);
          // This array of length n will hold the diagonal elements of the
          // upper triangular matrix s.
          Darray Sdiag(n_, 0.0);

          // Copy R and Qt_r to preserve input and initialize s.
          for (dsize in = 0; in != n_; in++) {
            for (dsize i = in; i != n_; i++)
              jacobian_[i + in * m_] = jacobian_[in + i * m_];
            Xvec[in] = jacobian_[in + in * m_];
            work2[in] = Qt_r[in];
          }

          // Eliminate the diagonal matrix D using a Givens rotation
          for (dsize in = 0; in != n_; in++) {
            // Prepare the row of D to be eliminated, locating the diagonal 
            // element using p from the QR factorization.
            double diagL = work1[ Jpvt[in] ];
            DBGPRINT("diag[%i] = %g\n", Jpvt[in]+1, diagL);
            if (diagL != 0.0) {
              for (dsize k = in; k < n_; k++)
                Sdiag[k] = 0.0;
              Sdiag[in] = diagL;
              // The transformations to eliminate the row of D modify only
              // a single element of Qt_r beyond the first n, which is 
              // initially zero.
              double qtbpj = 0.0;
              for (dsize k = in; k < n_; k++) {
                // Determine a Givens rotation which eliminates the appropriate
                // element in the current row of D.
                if (Sdiag[k] != 0.0) {
                  double d1 = jacobian_[k + k * m_];
                  double cos, sin;
                  if (fabs(d1) < fabs(Sdiag[k])) {
                    double cotan = jacobian_[k + k * m_] / Sdiag[k];
                    sin = 0.5 / sqrt(0.25 + 0.25 * (cotan * cotan));
                    cos = sin * cotan;
                  } else {
                    double tan = Sdiag[k] / jacobian_[k + k *m_];
                    cos = 0.5 / sqrt(0.25 + 0.25 * (tan * tan));
                    sin = cos * tan;
                  }
                  DBGPRINT("DBG QRsolv: %lu, %lu: cos= %12.6g  sin= %12.6g\n",
                         in+1, k+1, cos, sin);
                  // Compute the modified diagonal element of R and the 
                  // modified element of (Qt_r, 0)
                  jacobian_[k + k * m_] = cos * jacobian_[k + k * m_] + sin * Sdiag[k];
                  double temp = cos * work2[k] + sin * qtbpj; 
                  qtbpj = -sin * work2[k] + cos * qtbpj;
                  work2[k] = temp;
                  DBGPRINT("\twork2[%lu]= %g\n", k+1, work2[k]);
                  // Accumulate the transformation in the row of S
                  dsize kp1 = k + 1;
                  if (kp1 <= n_) {
                    for (dsize i = kp1; i < n_; i++) {
                      temp = cos * jacobian_[i + k * m_] + sin * Sdiag[i];
                      Sdiag[i] = -sin * jacobian_[i + k * m_] + cos * Sdiag[i];
                      jacobian_[i + k * m_] = temp;
                    }
                  }
                }
              }
            }
            // Store the diagonal element of s and restore the corresponding
            // diagonal element of r
            Sdiag[in] = jacobian_[in + in * m_];
            DBGPRINT("QRsolv sdiag[%lu]= %g\n", in+1, Sdiag[in]);
            jacobian_[in + in * m_] = Xvec[in];
          }
  
          // Solve the triangular system for z. if the system is singular,
          // then obtain a least-squares solution.
          dsize u_nsing = n_;
          for (dsize in = 0; in != n_; in++) {
            if (Sdiag[in] == 0.0 && u_nsing == n_)
              u_nsing = in;
            if (u_nsing < n_)
              work2[in] = 0.0;
          }
          DBGPRINT("nsing= %lu\n", u_nsing);
          // Subtract 1 from nsing to use as an index.
          long int nsing = (long int)u_nsing - 1;
          if (nsing >= 0) {
            for (long int k = 0; k <= nsing; k++) {
              long int in = nsing - k;
              double sum = 0.0;
              long int in1 = in + 1;
              if (in1 <= nsing) {
                for (long int i = in1; i <= nsing; i++)
                  sum += jacobian_[i + in * (long int)m_] * work2[i];
              }
              work2[in] = (work2[in] - sum) / Sdiag[in];
            }
          }

          // Permute the components of z back to components of x.
          for (dsize in = 0; in != n_; in++)
            Xvec[ Jpvt[in] ] = work2[in];

          PrintVector("QRsolv Xvec", Xvec);
          PrintVector("sdiag", Sdiag);
          // -----------------------------------------------
          // | END QRSOLV
          // -----------------------------------------------

          for (dsize in = 0; in != n_; in++) {
            work2[in] = diag[in] * Xvec[in];
            DBGPRINT("\twork2[%lu]= %g = %g * %g\n", in+1, work2[in], diag[in], Xvec[in]);
          }
  
          dxnorm = VecNorm( work2 );
          temp = fp;
          fp = dxnorm - delta;
          DBGPRINT("DBG LMPAR: fp = %g = %g - %g\n", fp, dxnorm, delta); 
          // If the function is small enough, accept the current value of LM_par.
          // Also test for the exceptional cases where parl is zero of the number
          // of iterations has reached 10.
          if (fabs(fp) <= 0.1 * delta ||
              (parl == 0.0 && fp <= temp && temp < 0.0) ||
              lmIterations == 10)
          {
            lmLoop = false;
            break;
          }
  
          // Compute the Newton correction.
          for (dsize in = 0; in != n_; in++) {
            int idx = Jpvt[ in ];
            work1[in] = diag[idx] * (work2[idx] / dxnorm);
          }
          for (dsize in = 0; in != n_; in++) {
            work1[in] /= Sdiag[in];
            temp = work1[in];
            dsize in1 = in + 1;
            if (in1 <= n_) {
              for (dsize i = in1; i < n_; i++)
                work1[i] -= jacobian_[i + in * m_] * temp;
            }
          }
          temp = VecNorm( work1 );
          double parc = fp / delta / temp / temp;
          DBGPRINT("parc= %g\n", parc);
          
          // Depending on the sign of the function, update parl or paru
          if (fp > 0.0)
            parl = std::max( parl, LM_par );
          if (fp < 0.0)
            paru = std::min( paru, LM_par );

          // Compute an improved estimate for the parameter
          LM_par = std::max( parl, LM_par + parc );
        }
      }
      DBGPRINT("END LMPAR iter= %i  LM_par= %g\n", lmIterations, LM_par); 
      if (lmIterations == 0)
        LM_par = 0.0;
      // -------------------------------------------
      // | LMPAR END
      // -------------------------------------------
      DBGPRINT("DEBUG: LM_par is %g\n", LM_par);
      // Store the direction Xvec and Param + Xvec. Calculate norm of Param.
      PrintVector("DEBUG: hvec", Xvec);
      for (dsize in = 0; in != n_; in++) {
        Xvec[in] = -Xvec[in];
        work1[in] = Params_[in] + Xvec[in];
        work2[in] = diag[in] * Xvec[in];
      }
      double pnorm = VecNorm( work2 );
      DBGPRINT("pnorm= %g\n", pnorm);

      // On first iteration, adjust initial step bound
      if (currentIt == 0)
        delta = std::min( delta, pnorm );
      DBGPRINT("Delta is now %g\n", delta);

      // Evaluate function at Param + Xvec and calculate its norm
      EvaluateFxn( Xvals_, Yvals_, work1, newResidual );
      ++nfev;
      double rnorm1 = VecNorm( newResidual );
      DBGPRINT("rnorm1= %g\n", rnorm1);

      // Compute the scaled actual reduction
      double actual_reduction = -1.0;
      if ( 0.1 * rnorm1 < rnorm) {
        double d1 = rnorm1 / rnorm;
        actual_reduction = 1.0 - d1 * d1;
      }
      DBGPRINT("actualReduction= %g\n", actual_reduction);

      // Compute the scaled predicted reduction and the scaled directional
      // derivative.
      for (dsize in = 0; in != n_; in++)
      {
        work2[in] = 0.0;
        double temp = Xvec[ Jpvt[in] ];
        for (dsize i = 0; i <= in; i++)
          work2[i] += jacobian_[i + in * m_] * temp;
      }
      double temp1 = VecNorm( work2 ) / rnorm;
      double temp2 = sqrt(LM_par) * pnorm / rnorm;
      DBGPRINT("temp1= %g    temp2= %g\n", temp1, temp2);

      double predicted_reduction = temp1 * temp1 + temp2 * temp2 / 0.5;
      double dirder = -(temp1 * temp1 + temp2 * temp2);
      DBGPRINT("predictedReduction = %12.6g    dirder= %12.6g\n", predicted_reduction, dirder);

      // Compute the ratio of the actial to the predicted reduction.
      if (predicted_reduction != 0.0)
        Ratio = actual_reduction / predicted_reduction;
      DBGPRINT("ratio= %g\n", Ratio);

      // Update the step bound
      if (Ratio <= 0.25) {
        DBGPRINT("Ratio <= 0.25\n");
        double temp;
        if (actual_reduction < 0.0)
          temp = 0.5 * dirder / (dirder + 0.5 * actual_reduction);
        else
          temp = 0.5;
        if ( 0.1 * rnorm1 >= rnorm || temp < 0.1 )
          temp = 0.1;
        DBGPRINT("delta = %g * min( %g, %g )\n", temp, delta, pnorm / 0.1); 
        delta = temp * std::min( delta, pnorm / 0.1 );
        LM_par /= temp;
      } else {
        if (LM_par == 0.0 || Ratio >= 0.75) {
          DBGPRINT("Ratio > 0.25 and (LMpar is zero or Ratio >= 0.75\n");
          delta = pnorm / 0.5;
          LM_par *= 0.5;
        }
      }
      DBGPRINT("LM_par= %g    Delta= %g\n", LM_par, delta);

      if (Ratio >= 0.0001) { 
        // Successful iteration. Update Param, residual, and their norms.
        for (dsize in = 0; in != n_; in++) {
          Params_[in] = work1[in];
          work1[in] = diag[in] * Params_[in];
        }
        for (dsize im = 0; im < m_; im++)
          residual_[im] = newResidual[im];
        xnorm = VecNorm( work1 );
        rnorm = rnorm1;
      }
      
      // Tests for convergence
      if (fabs(actual_reduction) <= tolerance &&
          predicted_reduction <= tolerance &&
          0.5 * Ratio <= 1.0)
        info = 1;
      if (delta <= xtol * xnorm)
        info = 2;  
      if (fabs(actual_reduction) <= tolerance &&
          predicted_reduction <= tolerance &&
          0.5 * Ratio <= 1.0 &&
          info == 2)
        info = 3;
      if (info != 0) break;
                 
      // Tests for stringent tolerance
      if (nfev >= maxfev)
        info = 5;
      if (fabs(actual_reduction) <= machine_epsilon &&
          predicted_reduction <= machine_epsilon &&
          0.5 * Ratio <= 1.0)
        info = 6;
      if (delta <= machine_epsilon * xnorm)
        info = 7;
      if (gnorm <= machine_epsilon)
        info = 8;
      if (info != 0) break;

    } // END inner loop
    if (info != 0) break;
    currentIt++;
  }
  // Final parameters and Y at final parameters
  Params_to_Pvec(ParamVec, Params_);
  fxn_(Xvals_, ParamVec, finalY_);
# ifdef DBG_CURVEFIT
  DBGPRINT("%s\n", Message(info));
  DBGPRINT("Exiting with info value = %i\n", info);
  for (dsize in = 0; in != n_; in++)
    DBGPRINT("\tParams[%lu]= %g\n", in, ParamVec[in]);
# endif
  return info;
}
Ejemplo n.º 16
0
// CurveFit::ParametersHaveProblems()
bool CurveFit::ParametersHaveProblems(Darray const& Xvals_, Darray const& Yvals_,
                                      Darray const& ParamsIn)
{
  if (ParamsIn.empty() || Xvals_.empty() || Yvals_.empty()) {
    errorMessage_ = "Parameters or coordinates are empty.";
    return true;
  }
  if (Xvals_.size() != Yvals_.size()) {
    errorMessage_ = "Number of X values != number of Y values.";
    return true;
  }
  if ( Xvals_.size() < ParamsIn.size() ) {
    errorMessage_ = "Number of parameters cannot be greater than number of XY values.";
    return true;
  }
  if (hasBounds_.empty())
    hasBounds_.assign(ParamsIn.size(), false);
  else {
    if (hasBounds_.size() != ParamsIn.size() ||
        Ubound_.size() != ParamsIn.size() ||
        Lbound_.size() != ParamsIn.size())
    {
      errorMessage_ = "Number of bounds does not match number of parameters.";
      return true;
    }
    for (dsize in = 0; in != ParamsIn.size(); in++) {
      if (hasBounds_[in]) {
        if ( Lbound_[in] >= Ubound_[in] ) {
          errorMessage_ = "Lower bound must be less than upper bound.";
          return true;
        }
        if (ParamsIn[in] <= Lbound_[in] ||
            ParamsIn[in] >= Ubound_[in])
        {
          errorMessage_ = "Initial parameter not within bounds.";
          return true;
        }
      }
    }
  }
  if (!Weights_.empty() && Weights_.size() != Xvals_.size()) {
    errorMessage_ = "Number of weights does not match number of XY values.";
    return true;
  }
  errorMessage_ = 0;
  return false;
}