<commit_before>/*
    Copyright (C) 2013  Martin Klapetek <mklapetek@kde.org>

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "personsmodelfeature.h"

#include <Nepomuk2/Vocabulary/NCO>

class PersonsModelFeaturePrivate : public QSharedData
{
public:
    QHash<QString, int> bindingsMap;
    QString queryPart;
    bool isOptional;
    QUrl watcherProperty;
};

PersonsModelFeature::PersonsModelFeature()
: d (new PersonsModelFeaturePrivate)
{
}

PersonsModelFeature::PersonsModelFeature(const PersonsModelFeature &other)
: d (other.d)
{
}

PersonsModelFeature::~PersonsModelFeature()
{
    //note do not need to delete d as it is a QSharedData
}

PersonsModelFeature& PersonsModelFeature::operator=(const PersonsModelFeature& other)
{
    if (this == &other) {
        return *this; //Protect against self-assignment
    }
    d = other.d;
    return *this;
}

QHash<QString, int> PersonsModelFeature::bindingsMap() const
{
    return d->bindingsMap;
}

void PersonsModelFeature::setBindingsMap(QHash<QString, int> bindingsMap)
{
    d->bindingsMap = bindingsMap;
}

void PersonsModelFeature::setQueryPart(const QString &part)
{
    d->queryPart = part;
}

QString PersonsModelFeature::queryPart() const
{
    if (d->isOptional) {
        return QString("OPTIONAL { %1 } ").arg(d->queryPart);
    } else {
        return d->queryPart;
    }
}

bool PersonsModelFeature::isOptional() const
{
    return d->isOptional;
}

void PersonsModelFeature::setOptional(bool optional)
{
    d->isOptional = optional;
}

QUrl PersonsModelFeature::watcherProperty() const
{
    return d->watcherProperty;
}

void PersonsModelFeature::setWatcherProperty(const QUrl &property)
{
    d->watcherProperty = property;
}

PersonsModelFeature PersonsModelFeature::avatarModelFeature(bool optional)
{
    PersonsModelFeature avatarsFeature;
    avatarsFeature.setQueryPart(QString::fromUtf8(
        "?uri      nco:photo    ?phRes. "
        "?phRes    nie:url      ?nie_url. "));
    QHash<QString, int> pb;
    pb.insert("nie_url", PersonsModel::PhotosRole);
    avatarsFeature.setBindingsMap(pb);
    avatarsFeature.setOptional(optional);
    avatarsFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::photo());
    return avatarsFeature;
}

PersonsModelFeature PersonsModelFeature::emailModelFeature(bool optional)
{
    PersonsModelFeature emailsFeature;
    emailsFeature.setQueryPart(QString::fromUtf8(
        "?uri                    nco:hasEmailAddress    ?nco_hasEmailAddress. "
        "?nco_hasEmailAddress    nco:emailAddress       ?nco_emailAddress. "));
    QHash<QString, int> eb;
    eb.insert("nco_emailAddress", PersonsModel::EmailsRole);
    emailsFeature.setBindingsMap(eb);
    emailsFeature.setOptional(optional);
    emailsFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::hasEmailAddress());
    return emailsFeature;
}

PersonsModelFeature PersonsModelFeature::fullNameModelFeature(bool optional)
{
    PersonsModelFeature fullNameFeature;
    fullNameFeature.setQueryPart(QString::fromUtf8(
        "?uri                    nco:fullname    ?nco_fullname. "));
    QHash<QString, int> fnb;
    fnb.insert("nco_fullname", PersonsModel::FullNamesRole);
    fullNameFeature.setBindingsMap(fnb);
    fullNameFeature.setOptional(optional);
    return fullNameFeature;
}

PersonsModelFeature PersonsModelFeature::groupsModelFeature(bool optional)
{
    PersonsModelFeature groupsFeature;
    groupsFeature.setQueryPart(QString::fromUtf8(
        "?uri                   nco:belongsToGroup      ?nco_belongsToGroup . "
        "?nco_belongsToGroup    nco:contactGroupName    ?nco_contactGroupName . "));
    QHash<QString, int> gb;
    gb.insert("nco_contactGroupName", PersonsModel::GroupsRole);
    groupsFeature.setBindingsMap(gb);
    groupsFeature.setOptional(optional);
    groupsFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::belongsToGroup());
    return groupsFeature;
}

PersonsModelFeature PersonsModelFeature::imModelFeature(bool optional)
{
    PersonsModelFeature imFeature;
    imFeature.setQueryPart(QString::fromUtf8(
        "?uri                 nco:hasIMAccount     ?nco_hasIMAccount. "
        "?nco_hasIMAccount    nco:imNickname       ?nco_imNickname. "
        "?nco_hasIMAccount    nco:imID             ?nco_imID. "));
    QHash<QString, int> b;
    b.insert("nco_imNickname", PersonsModel::NicknamesRole);
    b.insert("nco_imID", PersonsModel::IMsRole);
    imFeature.setBindingsMap(b);
    imFeature.setOptional(optional);
    imFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::hasIMAccount());
    return imFeature;
}
<commit_msg>Watch for nco:nickname<commit_after>/*
    Copyright (C) 2013  Martin Klapetek <mklapetek@kde.org>

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "personsmodelfeature.h"

#include <Nepomuk2/Vocabulary/NCO>

class PersonsModelFeaturePrivate : public QSharedData
{
public:
    QHash<QString, int> bindingsMap;
    QString queryPart;
    bool isOptional;
    QUrl watcherProperty;
};

PersonsModelFeature::PersonsModelFeature()
: d (new PersonsModelFeaturePrivate)
{
}

PersonsModelFeature::PersonsModelFeature(const PersonsModelFeature &other)
: d (other.d)
{
}

PersonsModelFeature::~PersonsModelFeature()
{
    //note do not need to delete d as it is a QSharedData
}

PersonsModelFeature& PersonsModelFeature::operator=(const PersonsModelFeature& other)
{
    if (this == &other) {
        return *this; //Protect against self-assignment
    }
    d = other.d;
    return *this;
}

QHash<QString, int> PersonsModelFeature::bindingsMap() const
{
    return d->bindingsMap;
}

void PersonsModelFeature::setBindingsMap(QHash<QString, int> bindingsMap)
{
    d->bindingsMap = bindingsMap;
}

void PersonsModelFeature::setQueryPart(const QString &part)
{
    d->queryPart = part;
}

QString PersonsModelFeature::queryPart() const
{
    if (d->isOptional) {
        return QString("OPTIONAL { %1 } ").arg(d->queryPart);
    } else {
        return d->queryPart;
    }
}

bool PersonsModelFeature::isOptional() const
{
    return d->isOptional;
}

void PersonsModelFeature::setOptional(bool optional)
{
    d->isOptional = optional;
}

QUrl PersonsModelFeature::watcherProperty() const
{
    return d->watcherProperty;
}

void PersonsModelFeature::setWatcherProperty(const QUrl &property)
{
    d->watcherProperty = property;
}

PersonsModelFeature PersonsModelFeature::avatarModelFeature(bool optional)
{
    PersonsModelFeature avatarsFeature;
    avatarsFeature.setQueryPart(QString::fromUtf8(
        "?uri      nco:photo    ?phRes. "
        "?phRes    nie:url      ?nie_url. "));
    QHash<QString, int> pb;
    pb.insert("nie_url", PersonsModel::PhotosRole);
    avatarsFeature.setBindingsMap(pb);
    avatarsFeature.setOptional(optional);
    avatarsFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::photo());
    return avatarsFeature;
}

PersonsModelFeature PersonsModelFeature::emailModelFeature(bool optional)
{
    PersonsModelFeature emailsFeature;
    emailsFeature.setQueryPart(QString::fromUtf8(
        "?uri                    nco:hasEmailAddress    ?nco_hasEmailAddress. "
        "?nco_hasEmailAddress    nco:emailAddress       ?nco_emailAddress. "));
    QHash<QString, int> eb;
    eb.insert("nco_emailAddress", PersonsModel::EmailsRole);
    emailsFeature.setBindingsMap(eb);
    emailsFeature.setOptional(optional);
    emailsFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::hasEmailAddress());
    return emailsFeature;
}

PersonsModelFeature PersonsModelFeature::fullNameModelFeature(bool optional)
{
    PersonsModelFeature fullNameFeature;
    fullNameFeature.setQueryPart(QString::fromUtf8(
        "?uri                    nco:fullname    ?nco_fullname. "));
    QHash<QString, int> fnb;
    fnb.insert("nco_fullname", PersonsModel::FullNamesRole);
    fullNameFeature.setBindingsMap(fnb);
    fullNameFeature.setOptional(optional);
    return fullNameFeature;
}

PersonsModelFeature PersonsModelFeature::groupsModelFeature(bool optional)
{
    PersonsModelFeature groupsFeature;
    groupsFeature.setQueryPart(QString::fromUtf8(
        "?uri                   nco:belongsToGroup      ?nco_belongsToGroup . "
        "?nco_belongsToGroup    nco:contactGroupName    ?nco_contactGroupName . "));
    QHash<QString, int> gb;
    gb.insert("nco_contactGroupName", PersonsModel::GroupsRole);
    groupsFeature.setBindingsMap(gb);
    groupsFeature.setOptional(optional);
    groupsFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::belongsToGroup());
    return groupsFeature;
}

PersonsModelFeature PersonsModelFeature::imModelFeature(bool optional)
{
    PersonsModelFeature imFeature;
    imFeature.setQueryPart(QString::fromUtf8(
        "?uri                 nco:hasIMAccount     ?nco_hasIMAccount. "
        "?nco_hasIMAccount    nco:imNickname       ?nco_imNickname. "
        "?nco_hasIMAccount    nco:imID             ?nco_imID. "));
    QHash<QString, int> b;
    b.insert("nco_imNickname", PersonsModel::NicknamesRole);
    b.insert("nco_imID", PersonsModel::IMsRole);
    imFeature.setBindingsMap(b);
    imFeature.setOptional(optional);
    imFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::hasIMAccount());
    imFeature.setWatcherProperty(Nepomuk2::Vocabulary::NCO::nickname());
    return imFeature;
}
<|endoftext|>


<commit_before>/*
 * Host based encapsulated base sweeper.
 */

#ifndef _PFASST_ENCAPSULATED_HPP_
#define _PFASST_ENCAPSULATED_HPP_

#include <vector>

#include "pfasst-interfaces.hpp"
#include "pfasst-quadrature.hpp"

using namespace std;

namespace pfasst {
  namespace encap {

    typedef enum EncapType { solution, function } EncapType;

    //
    // encapsulation
    //
    template<typename scalar>
    class Encapsulation {
    public:
      virtual ~Encapsulation() { }

      // required for time-parallel communications
      virtual void send() {
	throw NotImplementedYet("pfasst");
      }
      virtual void recv() {
	throw NotImplementedYet("pfasst");
      }

      // required for host based encap helpers
      virtual void setval(scalar) {
	throw NotImplementedYet("encap");
      }
      virtual void copy(const Encapsulation<scalar> *) {
	throw NotImplementedYet("encap");
      }
      virtual void saxpy(scalar a, const Encapsulation<scalar> *) {
	throw NotImplementedYet("encap");
      }
      virtual void mat_apply(vector<Encapsulation<scalar>*> dst, scalar a, matrix<scalar> m,
			     vector<Encapsulation<scalar>*> src, bool zero=true) {
        throw NotImplementedYet("encap");
      }
    };

    template<typename scalar>
    class EncapsulationFactory {
    public:
      virtual Encapsulation<scalar>* create(const EncapType) = 0;
    };

    template<typename scalar>
    class EncapsulatedSweeperMixin : public ISweeper {
      vector<scalar> nodes;
      shared_ptr<EncapsulationFactory<scalar>> factory;

    public:
      void set_nodes(vector<scalar> nodes) {
	this->nodes = nodes;      //
      }

      const vector<scalar> get_nodes() const {
	return nodes;
      }

      void set_factory(EncapsulationFactory<scalar>* factory) {
	this->factory = shared_ptr<EncapsulationFactory<scalar>>(factory);
      }

      EncapsulationFactory<scalar>* get_factory() const {
	return factory.get();
      }

      virtual void set_q(const Encapsulation<scalar>* q0, unsigned int m) {
	throw NotImplementedYet("sweeper");
      }

      virtual Encapsulation<scalar>* get_q(unsigned int m) const {
	throw NotImplementedYet("sweeper");
	return NULL;
      }

      virtual Encapsulation<scalar>* get_pq(unsigned int m) const {
	throw NotImplementedYet("sweeper");
	return NULL;
      }

      virtual Encapsulation<scalar>* get_qend() {
	return this->get_q(this->get_nodes().size()-1);
      }

      virtual void evaluate(int m) {
	throw NotImplementedYet("sweeper");
      }

      virtual void advance() {
	this->set_q(this->get_qend(), 0);
      }
    };

    template<typename scalar>
    class PolyInterpMixin : public pfasst::ITransfer {
      matrix<scalar> tmat;
    public:

      virtual void interpolate(ISweeper *DST, const ISweeper *SRC, bool initial) {
	auto* dst = dynamic_cast<EncapsulatedSweeperMixin<scalar>*>(DST);
	auto* src = dynamic_cast<const EncapsulatedSweeperMixin<scalar>*>(SRC);

	if (tmat.size1() == 0)
	  tmat = pfasst::compute_interp<scalar>(dst->get_nodes(), src->get_nodes());

	int ndst = dst->get_nodes().size();
	int nsrc = src->get_nodes().size();

	auto* crse_factory = src->get_factory();
	auto* fine_factory = dst->get_factory();

	vector<Encapsulation<scalar>*> fine_q(ndst), fine_tmp(ndst);

	for (int m=0; m<ndst; m++) fine_q[m]   = dst->get_q(m);
	for (int m=0; m<ndst; m++) fine_tmp[m] = fine_factory->create(solution);

	if (initial)
	  for (int m=1; m<ndst; m++)
	    fine_q[m]->copy(fine_q[0]);

	auto* crse_tmp = crse_factory->create(solution);
	for (int m=0; m<nsrc; m++) {
	  crse_tmp->copy(src->get_q(m));
	  if (initial)
	    crse_tmp->saxpy(-1.0, src->get_q(0));
	  else
	    crse_tmp->saxpy(-1.0, src->get_pq(m));
	  interpolate(fine_tmp[m], crse_tmp);
	}
	delete crse_tmp;

	dst->get_q(0)->mat_apply(fine_q, 1.0, tmat, fine_tmp, false);

	for (int m=0; m<ndst; m++) delete fine_tmp[m];
	for (int m=0; m<ndst; m++) dst->evaluate(m);

      }

      virtual void restrict(ISweeper *DST, const ISweeper *SRC) {
	auto* dst = dynamic_cast<EncapsulatedSweeperMixin<scalar>*>(DST);
	auto* src = dynamic_cast<const EncapsulatedSweeperMixin<scalar>*>(SRC);

	auto dnodes = dst->get_nodes();
	auto snodes = src->get_nodes();

	int ndst = dst->get_nodes().size();
	int nsrc = src->get_nodes().size();

	int trat = (nsrc - 1) / (ndst - 1);

	for (int m=0; m<ndst; m++) {
	  if (dnodes[m] != snodes[m*trat])
	    throw NotImplementedYet("coarse nodes must be nested");
	  this->restrict(dst->get_q(m), src->get_q(m*trat));
	}

	for (int m=0; m<ndst; m++) dst->evaluate(m);
      }

      // required for interp/restrict helpers
      virtual void interpolate(Encapsulation<scalar> *dst, const Encapsulation<scalar> *src) {
	throw NotImplementedYet("mlsdc/pfasst");
      }

      virtual void restrict(Encapsulation<scalar> *dst, const Encapsulation<scalar> *src) {
	throw NotImplementedYet("mlsdc/pfasst");
      }

    };

  }
}

#endif
<commit_msg>encap: Stop wasting space during interpolation.<commit_after>/*
 * Host based encapsulated base sweeper.
 */

#ifndef _PFASST_ENCAPSULATED_HPP_
#define _PFASST_ENCAPSULATED_HPP_

#include <vector>

#include "pfasst-interfaces.hpp"
#include "pfasst-quadrature.hpp"

using namespace std;

namespace pfasst {
  namespace encap {

    typedef enum EncapType { solution, function } EncapType;

    //
    // encapsulation
    //
    template<typename scalar>
    class Encapsulation {
    public:
      virtual ~Encapsulation() { }

      // required for time-parallel communications
      virtual void send() {
	throw NotImplementedYet("pfasst");
      }
      virtual void recv() {
	throw NotImplementedYet("pfasst");
      }

      // required for host based encap helpers
      virtual void setval(scalar) {
	throw NotImplementedYet("encap");
      }
      virtual void copy(const Encapsulation<scalar> *) {
	throw NotImplementedYet("encap");
      }
      virtual void saxpy(scalar a, const Encapsulation<scalar> *) {
	throw NotImplementedYet("encap");
      }
      virtual void mat_apply(vector<Encapsulation<scalar>*> dst, scalar a, matrix<scalar> m,
			     vector<Encapsulation<scalar>*> src, bool zero=true) {
        throw NotImplementedYet("encap");
      }
    };

    template<typename scalar>
    class EncapsulationFactory {
    public:
      virtual Encapsulation<scalar>* create(const EncapType) = 0;
    };

    template<typename scalar>
    class EncapsulatedSweeperMixin : public ISweeper {
      vector<scalar> nodes;
      shared_ptr<EncapsulationFactory<scalar>> factory;

    public:
      void set_nodes(vector<scalar> nodes) {
	this->nodes = nodes;      //
      }

      const vector<scalar> get_nodes() const {
	return nodes;
      }

      void set_factory(EncapsulationFactory<scalar>* factory) {
	this->factory = shared_ptr<EncapsulationFactory<scalar>>(factory);
      }

      EncapsulationFactory<scalar>* get_factory() const {
	return factory.get();
      }

      virtual void set_q(const Encapsulation<scalar>* q0, unsigned int m) {
	throw NotImplementedYet("sweeper");
      }

      virtual Encapsulation<scalar>* get_q(unsigned int m) const {
	throw NotImplementedYet("sweeper");
	return NULL;
      }

      virtual Encapsulation<scalar>* get_pq(unsigned int m) const {
	throw NotImplementedYet("sweeper");
	return NULL;
      }

      virtual Encapsulation<scalar>* get_qend() {
	return this->get_q(this->get_nodes().size()-1);
      }

      virtual void evaluate(int m) {
	throw NotImplementedYet("sweeper");
      }

      virtual void advance() {
	this->set_q(this->get_qend(), 0);
      }
    };

    template<typename scalar>
    class PolyInterpMixin : public pfasst::ITransfer {
      matrix<scalar> tmat;
    public:

      virtual void interpolate(ISweeper *DST, const ISweeper *SRC, bool initial) {
	auto* dst = dynamic_cast<EncapsulatedSweeperMixin<scalar>*>(DST);
	auto* src = dynamic_cast<const EncapsulatedSweeperMixin<scalar>*>(SRC);

	if (tmat.size1() == 0)
	  tmat = pfasst::compute_interp<scalar>(dst->get_nodes(), src->get_nodes());

	int ndst = dst->get_nodes().size();
	int nsrc = src->get_nodes().size();

	auto* crse_factory = src->get_factory();
	auto* fine_factory = dst->get_factory();

	vector<Encapsulation<scalar>*> fine_q(ndst), fine_tmp(nsrc);

	for (int m=0; m<ndst; m++) fine_q[m]   = dst->get_q(m);
	for (int m=0; m<nsrc; m++) fine_tmp[m] = fine_factory->create(solution);

	if (initial)
	  for (int m=1; m<ndst; m++)
	    fine_q[m]->copy(fine_q[0]);

	auto* crse_tmp = crse_factory->create(solution);
	for (int m=0; m<nsrc; m++) {
	  crse_tmp->copy(src->get_q(m));
	  if (initial)
	    crse_tmp->saxpy(-1.0, src->get_q(0));
	  else
	    crse_tmp->saxpy(-1.0, src->get_pq(m));
	  interpolate(fine_tmp[m], crse_tmp);
	}
	delete crse_tmp;

	dst->get_q(0)->mat_apply(fine_q, 1.0, tmat, fine_tmp, false);

	for (int m=0; m<nsrc; m++) delete fine_tmp[m];
	for (int m=0; m<ndst; m++) dst->evaluate(m);

      }

      virtual void restrict(ISweeper *DST, const ISweeper *SRC) {
	auto* dst = dynamic_cast<EncapsulatedSweeperMixin<scalar>*>(DST);
	auto* src = dynamic_cast<const EncapsulatedSweeperMixin<scalar>*>(SRC);

	auto dnodes = dst->get_nodes();
	auto snodes = src->get_nodes();

	int ndst = dst->get_nodes().size();
	int nsrc = src->get_nodes().size();

	int trat = (nsrc - 1) / (ndst - 1);

	for (int m=0; m<ndst; m++) {
	  if (dnodes[m] != snodes[m*trat])
	    throw NotImplementedYet("coarse nodes must be nested");
	  this->restrict(dst->get_q(m), src->get_q(m*trat));
	}

	for (int m=0; m<ndst; m++) dst->evaluate(m);
      }

      // required for interp/restrict helpers
      virtual void interpolate(Encapsulation<scalar> *dst, const Encapsulation<scalar> *src) {
	throw NotImplementedYet("mlsdc/pfasst");
      }

      virtual void restrict(Encapsulation<scalar> *dst, const Encapsulation<scalar> *src) {
	throw NotImplementedYet("mlsdc/pfasst");
      }

    };

  }
}

#endif
<|endoftext|>


<commit_before>#include "RhoZ.h"
#include "Units.h"
#include "PointContact.h"
using namespace GeFiCa;

void RhoZ::GetBoundaryConditionFrom(Detector &detector)
{
   Grid::GetBoundaryConditionFrom(detector); // check number of calls

   TString type(detector.ClassName());
   if (type.Contains("PointContact")) {
      if (N1%2==1) { // we want no grid point right on z-axis
         Error("GetBoundaryConditionFrom",
               "Please assign even number of grid points along radius.");
         abort();
      }
      PointContact& pc = (PointContact&) detector;
      pc.CheckConfigurations();
      GetInfoFrom(pc);
   } else {
      Error("GetBoundaryConditionFrom", "%s is not expected.", type.Data());
      Error("GetBoundaryConditionFrom", "Please use "
            "PointContact or Segmented detector.");
      abort();
   }

   fDetector = &detector; // for GetC to use fDetector->Bias[]
}
//______________________________________________________________________________
//
void RhoZ::OverRelaxAt(size_t idx)
{
   if (fIsFixed[idx]) return; // no need to calculate on boundaries

   double vzm; // previous(minus) Vp along z
   if (idx>=N1) vzm=Vp[idx-N1];
   else vzm=Vp[idx+N1]; // mirroring potential for bottom grid points

   double vnew=(Src[idx]+1/C1[idx]*(Vp[idx+1]-Vp[idx-1])/(dC1m[idx]+dC1p[idx])
         +(Vp[idx+1]/dC1p[idx]+Vp[idx-1]/dC1m[idx])*2/(dC1m[idx]+dC1p[idx])
         + (Vp[idx+N1]/dC2p[idx]+vzm/dC2m[idx])*2/(dC2p[idx]+dC2m[idx]))/
      ((1/dC1m[idx]+1/dC1p[idx])*2/(dC1m[idx]+dC1p[idx])
       +(1/dC2p[idx]+1/dC2m[idx])*2/(dC2p[idx]+dC2m[idx]));
   vnew=RelaxationFactor*(vnew-Vp[idx])+Vp[idx]; // over relax

   double vmin=Vp[idx-1]; // minimal Vp around point[idx]
   if(vmin>Vp[idx+1]) vmin=Vp[idx+1];
   if (vmin>Vp[idx+N1]) vmin=Vp[idx+N1];
   if (vmin>vzm) vmin=vzm;

   double vmax=Vp[idx-1]; // maximal Vp around point[idx]
   if (vmax<Vp[idx+1]) vmax=Vp[idx+1];
   if (vmax<Vp[idx+N1]) vmax=Vp[idx+N1];
   if (vmax<vzm) vmax=vzm;

   if (vnew<vmin) {
      Vp[idx]=vmin; fIsDepleted[idx]=false;
   } else if (vnew>vmax) {
      Vp[idx]=vmax; fIsDepleted[idx]=false;
   } else {
      Vp[idx]=vnew; fIsDepleted[idx]=true;
   }
   // update Vp for impurity-only case even if the point is undepleted
   if (fDetector->Bias[0]==fDetector->Bias[1]) Vp[idx]=vnew;
}
//______________________________________________________________________________
//
double RhoZ::GetC()
{
   Grid::GetC(); // calculate field excluding undepleted region

   // calculate C based on CV^2/2 = epsilon int E^2 dx^3 / 2
   PointContact& pc = (PointContact&) *fDetector;
   double dV=pc.Bias[0]-pc.Bias[1]; if(dV<0)dV=-dV;
   double SumofElectricField=0;
   for(size_t i=0;i<GetN();i++) {
      double e1=E1[i];
      double e2=E2[i];
      double dr=dC1p[i];
      double dz=dC2p[i];
      SumofElectricField+=(e1*e1+e2*e2)*C1[i]*dr*dz;
   }
   double c=SumofElectricField*2*3.14159*epsilon/dV/dV;
   Info("GetC","%.2f pF",c/pF);
   return c;
}
//______________________________________________________________________________
//
void RhoZ::GetInfoFrom(PointContact& pc)
{
   // set positions of grid points
   for (size_t i=0; i<N1; i++) { // bottom line
      dC1p.push_back(2*pc.Radius/(N1-1)); dC1m.push_back(2*pc.Radius/(N1-1));
      dC2p.push_back(pc.Height/(N2-1));
      dC2m.push_back(pc.Height/(N2-1)); // there are mirrored points below
      C1.push_back(-pc.Radius+i*dC1p[i]); C2.push_back(0);
      E1.push_back(0); E2.push_back(0); Et.push_back(0); Vp.push_back(0);
      fIsFixed.push_back(false); fIsDepleted.push_back(false);
      Src.push_back(-pc.GetImpurity(C2[i])*Qe/epsilon);
   }
   for (size_t i=N1; i<N1*N2; i++) { // the rest
      dC1p.push_back(2*pc.Radius/(N1-1)); dC1m.push_back(2*pc.Radius/(N1-1));
      dC2p.push_back(pc.Height/(N2-1)); dC2m.push_back(pc.Height/(N2-1));
      C1.push_back(C1[i-N1]); C2.push_back(C2[i-N1]+dC2p[i-N1]);
      E1.push_back(0); E2.push_back(0); Et.push_back(0); Vp.push_back(0);
      fIsFixed.push_back(false); fIsDepleted.push_back(false);
      Src.push_back(-pc.GetImpurity(C2[i])*Qe/epsilon);
   }
   // set impurity in groove and potentials of grid points
   size_t npc=0; // number of grid points in PC
   for (size_t i=N1*N2; i-->0;) {
      if (C1[i]>=-pc.PointContactR && C1[i]<=pc.PointContactR
            && C2[i]<=pc.PointContactH) { // point contact
         Vp[i]=pc.Bias[0]; fIsFixed[i]=true; npc++;
      } else if (C1[i]<=pc.BoreR && C1[i]>=-pc.BoreR
            && C2[i]>=pc.Height-pc.BoreH) { // bore hole
         Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
      } else if (((C1[i]>pc.WrapAroundR-pc.GrooveW && C1[i]<pc.WrapAroundR)
               || (C1[i]>-pc.WrapAroundR && C1[i]<-pc.WrapAroundR+pc.GrooveW))
            && C2[i]<pc.GrooveH) { // groove
         Vp[i]=pc.Bias[1]/4; Src[i]=0;
      } else // bulk
         Vp[i]=(pc.Bias[0]+pc.Bias[1])/2;
      double slope, intercept;
      if (pc.CornerW>0) { // has top taper
         slope=-pc.CornerH/pc.CornerW;
         intercept=pc.Height-slope*(pc.Radius-pc.CornerW);
         if (C2[i]>-slope*C1[i]+intercept||C2[i]>slope*C1[i]+intercept) {
            Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
         }
      }
      if (pc.TaperW>0) { // has bottom taper
         slope=pc.TaperH/(pc.TaperW);
         intercept=-(pc.Radius-pc.TaperW)*slope;
         if (C2[i]<=C1[i]*slope+intercept || C2[i]<=-C1[i]*slope+intercept) {
            Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
         }
      }
      if (pc.BoreTaperW>0) { // has bore taper
         slope=pc.BoreTaperH/pc.BoreTaperW;
         intercept=pc.Height-slope*(pc.BoreR+pc.BoreTaperW);
         if ((C2[i]>-slope*C1[i]+intercept && C1[i]<0) ||
               (C2[i]>slope*C1[i]+intercept && C1[i]>0)) {
            Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
         }
      }
   }
   if (npc<1) { Error("GetInfoFrom", "no point in point contact!"); abort(); }
   for (size_t i=N1*N2-1; i>=N1*N2-N1; i--) { // top boundary
      Vp[i]=pc.Bias[1]; fIsFixed[i]=true; dC2p[i]=0;
   }
   for (size_t i=0; i<N1*N2-N1; i=i+N1) { // left & right boundaries
      Vp[i]=pc.Bias[1]; Vp[i+N1-1]=pc.Bias[1];
      fIsFixed[i]=true; fIsFixed[i+N1-1]=true;
      dC1m[i]=0; dC1p[i+N1-1]=0;
   }
   for (size_t i=0; i<N1; i++) { // wrap arround
      if (C1[i]>=pc.WrapAroundR||C1[i]<=-pc.WrapAroundR) {
         fIsFixed[i]=true;
         Vp[i]=pc.Bias[1];
      }
   }

   ReallocateGridPointsNearBoundaries(pc);
}
//______________________________________________________________________________
//
void RhoZ::ReallocateGridPointsNearBoundaries(PointContact &pc)
{
   double slope, intercept;
   for (size_t i=0; i<GetN(); i++) {
      if (C2[i]-pc.PointContactH<dC2m[i] && C2[i]>pc.PointContactH
            && C1[i]<pc.PointContactR && C1[i]>-pc.PointContactR) {
         dC2m[i]=C2[i]-pc.PointContactH; // top of point contact
         // since C2[i] is too close to boundary, we regard it as on the boundary
         // Fixme: same protection should be applied to other boundaries
         if (dC2m[i]<1e-4*cm) { Vp[i]=pc.Bias[0]; fIsFixed[i]=true; }
      }
      if (C1[i]-pc.PointContactR<dC1m[i]&&C1[i]>0&&C2[i]<pc.PointContactH)
         dC1m[i]=C1[i]-pc.PointContactR; // right of point contact
      if (-C1[i]-pc.PointContactR<dC1p[i]&&C1[i]<0&&C2[i]<pc.PointContactH)
         dC1p[i]=-C1[i]-pc.PointContactR; // left of point contact
      //right side of bore
      if (C1[i]-pc.BoreR<dC1m[i] && C2[i]>pc.BoreH && C1[i]-pc.BoreR>0)
         dC1m[i]=C1[i]-pc.BoreR;
      //left side of bore
      if (-C1[i]-pc.BoreR>0&&-C1[i]-pc.BoreR<dC1p[i]&&C2[i]>pc.BoreH)
         dC1p[i]=-C1[i]-pc.BoreR;
      //down side of bore
      if (pc.Height-pc.BoreTaperH-C2[i]<dC2p[i]&&C1[i]>-pc.BoreR&&
            C1[i]<pc.BoreR) dC2p[i]=pc.Height-pc.BoreTaperH-C2[i];
      // Fixme: V around groove bounaries are all changable,
      // which should be reallocated?
      if (pc.WrapAroundR-C1[i]<dC1p[i]&&C1[i]<pc.WrapAroundR&&i<N1)
         dC1p[i]=pc.WrapAroundR-C1[i];
      if (pc.WrapAroundR+C1[i]<dC1p[i]&&C1[i]>-pc.WrapAroundR&&i<N1)
         dC1m[i]=pc.WrapAroundR+C1[i];
      if (pc.CornerW>0) { // has top taper
         slope=-pc.CornerH/pc.CornerW;
         intercept=pc.Height-slope*(pc.Radius-pc.CornerW);
         if (C1[i]+C2[i]/slope-intercept/slope>0 &&
               C1[i]+C2[i]/slope-intercept/slope<dC1m[i] &&
               C2[i]>pc.Height-pc.CornerH) // left
            dC1m[i]=C1[i]+C2[i]/slope-intercept/slope;
         if (-C1[i]+C2[i]/slope-intercept/slope>0 &&
               -C1[i]+C2[i]/slope-intercept/slope<dC1p[i] &&
               C2[i]>pc.Height-pc.CornerH) // right
            dC1p[i]=-C1[i]+C2[i]/slope-intercept/slope;
      }
      if (pc.TaperW>0) { // has bottom taper
         slope=pc.TaperH/pc.TaperW;
         intercept=-(pc.Radius-pc.TaperW)*slope;
         if (C2[i]-(slope*C1[i]+intercept)<dC2m[i]) // right side, C2
            dC2m[i]=C2[i]-(slope*C1[i]+intercept);
         if ((C2[i]-intercept)/slope-C1[i]<dC1p[i]) // right side, C1
            dC1p[i]=(C2[i]-intercept)/slope-C1[i];
         if (C2[i]-(-slope*C1[i]+intercept)<dC2m[i]) // left side, C2
            dC2m[i]=C2[i]-(-slope*C1[i]+intercept);
         if (C1[i]+(C2[i]-intercept)/slope<dC1m[i]) // left side, C1
            dC1m[i]=C1[i]+(C2[i]-intercept)/slope;
      }
      if (pc.BoreTaperW>0) { // has bore taper
         slope=pc.BoreTaperH/pc.BoreTaperW;
         intercept=pc.Height-slope*(pc.BoreR+pc.BoreTaperW);
         if (C1[i]-C2[i]/slope+intercept/slope<dC1m[i] &&
               C2[i]>pc.Height-pc.BoreTaperH &&
               C1[i]-C2[i]/slope+intercept/slope>0) //right side of hole taper
            dC1m[i]=C1[i]-C2[i]/slope+intercept/slope;
         if (-C1[i]-C2[i]/slope+intercept/slope>0 &&
               -C1[i]-C2[i]/slope+intercept/slope<dC1p[i] &&
               C2[i]>pc.Height-pc.BoreTaperH) //left side of hole taper
            dC1p[i]=-C1[i]-C2[i]/slope+intercept/slope;
      }
   }
}
<commit_msg>added protections<commit_after>#include "RhoZ.h"
#include "Units.h"
#include "PointContact.h"
using namespace GeFiCa;

void RhoZ::GetBoundaryConditionFrom(Detector &detector)
{
   Grid::GetBoundaryConditionFrom(detector); // check number of calls

   TString type(detector.ClassName());
   if (type.Contains("PointContact")) {
      if (N1%2==1) { // we want no grid point right on z-axis
         Error("GetBoundaryConditionFrom",
               "Please assign even number of grid points along radius.");
         abort();
      }
      PointContact& pc = (PointContact&) detector;
      pc.CheckConfigurations();
      GetInfoFrom(pc);
   } else {
      Error("GetBoundaryConditionFrom", "%s is not expected.", type.Data());
      Error("GetBoundaryConditionFrom", "Please use "
            "PointContact or Segmented detector.");
      abort();
   }

   fDetector = &detector; // for GetC to use fDetector->Bias[]
}
//______________________________________________________________________________
//
void RhoZ::OverRelaxAt(size_t idx)
{
   if (fIsFixed[idx]) return; // no need to calculate on boundaries

   double vzm; // previous(minus) Vp along z
   if (idx>=N1) vzm=Vp[idx-N1];
   else vzm=Vp[idx+N1]; // mirroring potential for bottom grid points

   double vnew=(Src[idx]+1/C1[idx]*(Vp[idx+1]-Vp[idx-1])/(dC1m[idx]+dC1p[idx])
         +(Vp[idx+1]/dC1p[idx]+Vp[idx-1]/dC1m[idx])*2/(dC1m[idx]+dC1p[idx])
         + (Vp[idx+N1]/dC2p[idx]+vzm/dC2m[idx])*2/(dC2p[idx]+dC2m[idx]))/
      ((1/dC1m[idx]+1/dC1p[idx])*2/(dC1m[idx]+dC1p[idx])
       +(1/dC2p[idx]+1/dC2m[idx])*2/(dC2p[idx]+dC2m[idx]));
   vnew=RelaxationFactor*(vnew-Vp[idx])+Vp[idx]; // over relax

   double vmin=Vp[idx-1]; // minimal Vp around point[idx]
   if(vmin>Vp[idx+1]) vmin=Vp[idx+1];
   if (vmin>Vp[idx+N1]) vmin=Vp[idx+N1];
   if (vmin>vzm) vmin=vzm;

   double vmax=Vp[idx-1]; // maximal Vp around point[idx]
   if (vmax<Vp[idx+1]) vmax=Vp[idx+1];
   if (vmax<Vp[idx+N1]) vmax=Vp[idx+N1];
   if (vmax<vzm) vmax=vzm;

   if (vnew<vmin) {
      Vp[idx]=vmin; fIsDepleted[idx]=false;
   } else if (vnew>vmax) {
      Vp[idx]=vmax; fIsDepleted[idx]=false;
   } else {
      Vp[idx]=vnew; fIsDepleted[idx]=true;
   }
   // update Vp for impurity-only case even if the point is undepleted
   if (fDetector->Bias[0]==fDetector->Bias[1]) Vp[idx]=vnew;
}
//______________________________________________________________________________
//
double RhoZ::GetC()
{
   Grid::GetC(); // calculate field excluding undepleted region

   // calculate C based on CV^2/2 = epsilon int E^2 dx^3 / 2
   PointContact& pc = (PointContact&) *fDetector;
   double dV=pc.Bias[0]-pc.Bias[1]; if(dV<0)dV=-dV;
   double SumofElectricField=0;
   for(size_t i=0;i<GetN();i++) {
      double e1=E1[i];
      double e2=E2[i];
      double dr=dC1p[i];
      double dz=dC2p[i];
      SumofElectricField+=(e1*e1+e2*e2)*C1[i]*dr*dz;
   }
   double c=SumofElectricField*2*3.14159*epsilon/dV/dV;
   Info("GetC","%.2f pF",c/pF);
   return c;
}
//______________________________________________________________________________
//
void RhoZ::GetInfoFrom(PointContact& pc)
{
   // set positions of grid points
   for (size_t i=0; i<N1; i++) { // bottom line
      dC1p.push_back(2*pc.Radius/(N1-1)); dC1m.push_back(2*pc.Radius/(N1-1));
      dC2p.push_back(pc.Height/(N2-1));
      dC2m.push_back(pc.Height/(N2-1)); // there are mirrored points below
      C1.push_back(-pc.Radius+i*dC1p[i]); C2.push_back(0);
      E1.push_back(0); E2.push_back(0); Et.push_back(0); Vp.push_back(0);
      fIsFixed.push_back(false); fIsDepleted.push_back(false);
      Src.push_back(-pc.GetImpurity(C2[i])*Qe/epsilon);
   }
   for (size_t i=N1; i<N1*N2; i++) { // the rest
      dC1p.push_back(2*pc.Radius/(N1-1)); dC1m.push_back(2*pc.Radius/(N1-1));
      dC2p.push_back(pc.Height/(N2-1)); dC2m.push_back(pc.Height/(N2-1));
      C1.push_back(C1[i-N1]); C2.push_back(C2[i-N1]+dC2p[i-N1]);
      E1.push_back(0); E2.push_back(0); Et.push_back(0); Vp.push_back(0);
      fIsFixed.push_back(false); fIsDepleted.push_back(false);
      Src.push_back(-pc.GetImpurity(C2[i])*Qe/epsilon);
   }
   // set impurity in groove and potentials of grid points
   size_t npc=0; // number of grid points in PC
   for (size_t i=N1*N2; i-->0;) {
      if (C1[i]>=-pc.PointContactR && C1[i]<=pc.PointContactR
            && C2[i]<=pc.PointContactH) { // point contact
         Vp[i]=pc.Bias[0]; fIsFixed[i]=true; npc++;
      } else if (C1[i]<=pc.BoreR && C1[i]>=-pc.BoreR
            && C2[i]>=pc.Height-pc.BoreH) { // bore hole
         Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
      } else if (((C1[i]>pc.WrapAroundR-pc.GrooveW && C1[i]<pc.WrapAroundR)
               || (C1[i]>-pc.WrapAroundR && C1[i]<-pc.WrapAroundR+pc.GrooveW))
            && C2[i]<pc.GrooveH) { // groove
         Vp[i]=pc.Bias[1]/4; Src[i]=0;
      } else // bulk
         Vp[i]=(pc.Bias[0]+pc.Bias[1])/2;
      double slope, intercept;
      if (pc.CornerW>0) { // has top taper
         slope=-pc.CornerH/pc.CornerW;
         intercept=pc.Height-slope*(pc.Radius-pc.CornerW);
         if (C2[i]>-slope*C1[i]+intercept||C2[i]>slope*C1[i]+intercept) {
            Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
         }
      }
      if (pc.TaperW>0) { // has bottom taper
         slope=pc.TaperH/(pc.TaperW);
         intercept=-(pc.Radius-pc.TaperW)*slope;
         if (C2[i]<=C1[i]*slope+intercept || C2[i]<=-C1[i]*slope+intercept) {
            Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
         }
      }
      if (pc.BoreTaperW>0) { // has bore taper
         slope=pc.BoreTaperH/pc.BoreTaperW;
         intercept=pc.Height-slope*(pc.BoreR+pc.BoreTaperW);
         if ((C2[i]>-slope*C1[i]+intercept && C1[i]<0) ||
               (C2[i]>slope*C1[i]+intercept && C1[i]>0)) {
            Vp[i]=pc.Bias[1]; fIsFixed[i]=true;
         }
      }
   }
   if (npc<1) { Error("GetInfoFrom", "no point in point contact!"); abort(); }
   for (size_t i=N1*N2-1; i>=N1*N2-N1; i--) { // top boundary
      Vp[i]=pc.Bias[1]; fIsFixed[i]=true; dC2p[i]=0;
   }
   for (size_t i=0; i<=N1*N2-N1; i=i+N1) { // left & right boundaries
      Vp[i]=pc.Bias[1]; Vp[i+N1-1]=pc.Bias[1];
      fIsFixed[i]=true; fIsFixed[i+N1-1]=true;
      dC1m[i]=0; dC1p[i+N1-1]=0;
   }
   for (size_t i=0; i<N1; i++) { // wrap arround
      if (C1[i]>=pc.WrapAroundR||C1[i]<=-pc.WrapAroundR) {
         fIsFixed[i]=true;
         Vp[i]=pc.Bias[1];
      }
   }

   ReallocateGridPointsNearBoundaries(pc);
}
//______________________________________________________________________________
//
void RhoZ::ReallocateGridPointsNearBoundaries(PointContact &pc)
{
   double slope, intercept;
   for (size_t i=0; i<GetN(); i++) {
      if (C2[i]-pc.PointContactH<dC2m[i] && C2[i]>pc.PointContactH
            && C1[i]<pc.PointContactR && C1[i]>-pc.PointContactR) {
         dC2m[i]=C2[i]-pc.PointContactH; // top of point contact
         // since C2[i] is too close to boundary, we regard it as on the boundary
         // Fixme: same protection should be applied to other boundaries
         if (dC2m[i]<1e-4*cm) { Vp[i]=pc.Bias[0]; fIsFixed[i]=true; }
      }
      if (C1[i]-pc.PointContactR<dC1m[i]&&C1[i]>pc.PointContactR
            &&C2[i]<pc.PointContactH)
         dC1m[i]=C1[i]-pc.PointContactR; // right of point contact
      if (-C1[i]-pc.PointContactR<dC1p[i]&&C1[i]<-pc.PointContactR
            &&C2[i]<pc.PointContactH)
         dC1p[i]=-C1[i]-pc.PointContactR; // left of point contact
      //right side of bore
      if (C1[i]-pc.BoreR>0&&C1[i]-pc.BoreR<dC1m[i]&&C2[i]>=pc.Height-pc.BoreH)
         dC1m[i]=C1[i]-pc.BoreR;
      //left side of bore
      if (-C1[i]-pc.BoreR>0&&-C1[i]-pc.BoreR<dC1p[i]&&C2[i]>=pc.Height-pc.BoreH)
         dC1p[i]=-C1[i]-pc.BoreR;
      //down side of bore
      if (pc.Height-pc.BoreTaperH-C2[i]<dC2p[i]&&C1[i]>-pc.BoreR&&
            C1[i]<pc.BoreR) dC2p[i]=pc.Height-pc.BoreTaperH-C2[i];
      // Fixme: V around groove bounaries are all changable,
      // which should be reallocated?
      if (pc.WrapAroundR-C1[i]<dC1p[i]&&C1[i]<pc.WrapAroundR&&i<N1)
         dC1p[i]=pc.WrapAroundR-C1[i];
      if (pc.WrapAroundR+C1[i]<dC1p[i]&&C1[i]>-pc.WrapAroundR&&i<N1)
         dC1m[i]=pc.WrapAroundR+C1[i];
      if (pc.CornerW>0) { // has top taper
         slope=-pc.CornerH/pc.CornerW;
         intercept=pc.Height-slope*(pc.Radius-pc.CornerW);
         if (C1[i]+C2[i]/slope-intercept/slope>0 &&
               C1[i]+C2[i]/slope-intercept/slope<dC1m[i] &&
               C2[i]>pc.Height-pc.CornerH) // left
            dC1m[i]=C1[i]+C2[i]/slope-intercept/slope;
         if (-C1[i]+C2[i]/slope-intercept/slope>0 &&
               -C1[i]+C2[i]/slope-intercept/slope<dC1p[i] &&
               C2[i]>pc.Height-pc.CornerH) // right
            dC1p[i]=-C1[i]+C2[i]/slope-intercept/slope;
      }
      if (pc.TaperW>0) { // has bottom taper
         slope=pc.TaperH/pc.TaperW;
         intercept=-(pc.Radius-pc.TaperW)*slope;
         if (C2[i]-(slope*C1[i]+intercept)<dC2m[i]
               && C2[i]-(slope*C1[i]+intercept)>0) // right side, C2
            dC2m[i]=C2[i]-(slope*C1[i]+intercept);
         if ((C2[i]-intercept)/slope-C1[i]<dC1p[i]
               && (C2[i]-intercept)/slope-C1[i]>0) // right side, C1
            dC1p[i]=(C2[i]-intercept)/slope-C1[i];
         if (C2[i]-(-slope*C1[i]+intercept)<dC2m[i]
               && C2[i]-(-slope*C1[i]+intercept)>0) // left side, C2
            dC2m[i]=C2[i]-(-slope*C1[i]+intercept);
         if (C1[i]+(C2[i]-intercept)/slope<dC1m[i]
               && C1[i]+(C2[i]-intercept)/slope>0) // left side, C1
            dC1m[i]=C1[i]+(C2[i]-intercept)/slope;
      }
      if (pc.BoreTaperW>0) { // has bore taper
         slope=pc.BoreTaperH/pc.BoreTaperW;
         intercept=pc.Height-slope*(pc.BoreR+pc.BoreTaperW);
         if (C1[i]-C2[i]/slope+intercept/slope<dC1m[i] &&
               C2[i]>pc.Height-pc.BoreTaperH &&
               C1[i]-C2[i]/slope+intercept/slope>0) //right side of hole taper
            dC1m[i]=C1[i]-C2[i]/slope+intercept/slope;
         if (-C1[i]-C2[i]/slope+intercept/slope>0 &&
               -C1[i]-C2[i]/slope+intercept/slope<dC1p[i] &&
               C2[i]>pc.Height-pc.BoreTaperH) //left side of hole taper
            dC1p[i]=-C1[i]-C2[i]/slope+intercept/slope;
      }
   }
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_draminit_training.C
/// @brief Train dram
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>

#include <p9_mss_draminit_training.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

extern "C"
{
    ///
    /// @brief Train dram
    /// @param[in] i_target, the McBIST of the ports of the dram you're training
    /// @param[in] i_special_training, optional CAL_STEP_ENABLE override. Used in sim, debug
    /// @return FAPI2_RC_SUCCESS iff ok
    ///
    fapi2::ReturnCode p9_mss_draminit_training( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
            const uint16_t i_special_training )
    {
        fapi2::buffer<uint16_t> l_cal_steps_enabled = i_special_training;

        FAPI_INF("Start draminit training");

        uint8_t l_reset_disable = 0;
        FAPI_TRY( mss::draminit_reset_disable(l_reset_disable) );

        // Configure the CCS engine.
        {
            fapi2::buffer<uint64_t> l_ccs_config;

            FAPI_TRY( mss::ccs::read_mode(i_target, l_ccs_config) );

            // It's unclear if we want to run with this true or false. Right now (10/15) this
            // has to be false. Shelton was unclear if this should be on or off in general BRS
            mss::ccs::stop_on_err(i_target, l_ccs_config, false);
            mss::ccs::ue_disable(i_target, l_ccs_config, false);
            mss::ccs::copy_cke_to_spare_cke(i_target, l_ccs_config, true);

            // Hm. Centaur sets this up for the longest duration possible. Can we do better?
            mss::ccs::cal_count(i_target, l_ccs_config, ~0, ~0);

#ifndef JIM_SAYS_TURN_OFF_ECC
            mss::ccs::disable_ecc(i_target, l_ccs_config);
#endif
            FAPI_TRY( mss::ccs::write_mode(i_target, l_ccs_config) );
        }

        // Clean out any previous calibration results, set bad-bits and configure the ranks.
        FAPI_DBG("MCA's on this McBIST: %d", i_target.getChildren<TARGET_TYPE_MCA>().size());

        for( auto p : i_target.getChildren<TARGET_TYPE_MCA>())
        {
            mss::ccs::program<TARGET_TYPE_MCBIST, TARGET_TYPE_MCA> l_program;

            // Setup a series of register probes which we'll see during the polling loop
            l_program.iv_probes =
            {
                // One block for each DP16
                {p, "wr_cntr_status0 (dp16 0)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_0},
                {p, "wr_cntr_status1 (dp16 0)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_0},
                {p, "wr_cntr_status2 (dp16 0)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_0},
                {p, "wr_lvl_status (dp16 0)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_0},

                {p, "wr_cntr_status0 (dp16 1)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_1},
                {p, "wr_cntr_status1 (dp16 1)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_1},
                {p, "wr_cntr_status2 (dp16 1)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_1},
                {p, "wr_lvl_status (dp16 1)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_1},

                {p, "wr_cntr_status0 (dp16 2)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_2},
                {p, "wr_cntr_status1 (dp16 2)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_2},
                {p, "wr_cntr_status2 (dp16 2)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_2},
                {p, "wr_lvl_status (dp16 2)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_2},

                {p, "wr_cntr_status0 (dp16 3)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_3},
                {p, "wr_cntr_status1 (dp16 3)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_3},
                {p, "wr_cntr_status2 (dp16 3)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_3},
                {p, "wr_lvl_status (dp16 3)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_3},

                {p, "wr_cntr_status0 (dp16 4)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_4},
                {p, "wr_cntr_status1 (dp16 4)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_4},
                {p, "wr_cntr_status2 (dp16 4)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_4},
                {p, "wr_lvl_status (dp16 4)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_4},
            };

            // Delays in the CCS instruction ARR1 for training are supposed to be 0xFFFF,
            // and we're supposed to poll for the done or timeout bit. But we don't want
            // to wait 0xFFFF cycles before we start polling - that's too long. So we put
            // in a best-guess of how long to wait. This, in a perfect world, would be the
            // time it takes one rank to train one training algorithm times the number of
            // ranks we're going to train. We fail-safe as worst-case we simply poll the
            // register too much - so we can tune this as we learn more.
            l_program.iv_poll.iv_initial_sim_delay = mss::DELAY_100US;
            l_program.iv_poll.iv_initial_sim_delay = 200;
            l_program.iv_poll.iv_poll_count = 0xFFFF;

            // Returned from set_rank_pairs, it tells us how many rank pairs
            // we configured on this port.
            std::vector<uint64_t> l_pairs;

#ifdef CAL_STATUS_DOESNT_REPORT_COMPLETE
            // This isn't correct - shouldn't be setting
            static const uint64_t CLEAR_CAL_COMPLETE = 0x000000000000F000;
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_STATUS_P0, CLEAR_CAL_COMPLETE) );
#endif
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_ERROR_P0, 0) );
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0, 0) );

            // Disable port fails as it doesn't appear the MC handles initial cal timeouts
            // correctly (cal_length.) BRS, see conversation with Brad Michael
            FAPI_TRY( mss::change_port_fail_disable(p, mss::ON ) );

            // The following registers must be configured to the correct operating environment:

            // Unclear, can probably be 0's for sim BRS
            // • Section 5.2.5.10 SEQ ODT Write Configuration {0-3} on page 422

            FAPI_TRY( mss::reset_seq_config0(p) );
            FAPI_TRY( mss::reset_seq_rd_wr_data(p) );

            FAPI_TRY( mss::reset_odt_config(p) );

            // These are reset in phy_scominit
            // • Section 5.2.6.1 WC Configuration 0 Register on page 434
            // • Section 5.2.6.2 WC Configuration 1 Register on page 436
            // • Section 5.2.6.3 WC Configuration 2 Register on page 438

            // Get our rank pairs.
            FAPI_TRY( mss::get_rank_pairs(p, l_pairs) );

            // Setup the config register
            //
            // Grab the attribute which contains the information on what cal steps we should run
            // if the i_specal_training bits have not been specified.
            if (i_special_training == 0)
            {
                FAPI_TRY( mss::cal_step_enable(p, l_cal_steps_enabled) );
            }

            FAPI_DBG("cal steps enabled: 0x%x special training: 0x%x", l_cal_steps_enabled, i_special_training);

            // Check to see if we're supposed to reset the delay values before starting training
            // don't reset if we're running special training - assumes there's a checkpoint which has valid state.
            if ((l_reset_disable == fapi2::ENUM_ATTR_MSS_DRAMINIT_RESET_DISABLE_ENABLE) && (i_special_training == 0))
            {
                FAPI_TRY( mss::dp16<TARGET_TYPE_MCA>().reset_delay_values(p, l_pairs) );
            }

            FAPI_DBG("generating calibration CCS instructions: %d rank-pairs", l_pairs.size());

            // For each rank pair we need to calibrate, pop a ccs instruction in an array and execute it.
            // NOTE: IF YOU CALIBRATE MORE THAN ONE RANK PAIR PER CCS PROGRAM, MAKE SURE TO CHANGE
            // THE PROCESSING OF THE ERRORS. (it's hard to figure out which DIMM failed, too) BRS.
            for (auto rp : l_pairs)
            {
                auto l_inst = mss::ccs::initial_cal_command<TARGET_TYPE_MCBIST>(rp);

                FAPI_DBG("exeecuting training CCS instruction: 0x%llx, 0x%llx", l_inst.arr0, l_inst.arr1);
                l_program.iv_instructions.push_back(l_inst);

                // We need to figure out how long to wait before we start polling. Each cal step has an expected
                // duration, so for each cal step which was enabled, we update the CCS program.
                FAPI_TRY( mss::cal_timer_setup(p, l_program.iv_poll, l_cal_steps_enabled) );
                FAPI_TRY( mss::setup_cal_config(p, rp, l_cal_steps_enabled) );

                // In the event of an init cal hang, CCS_STATQ(2) will assert and CCS_STATQ(3:5) = “001” to indicate a
                // timeout. Otherwise, if calibration completes, FW should inspect DDRPHY_FIR_REG bits (50) and (58)
                // for signs of a calibration error. If either bit is on, then the DDRPHY_PC_INIT_CAL_ERROR register
                // should be polled to determine which calibration step failed.

                // If we got a cal timeout, or another CCS error just leave now. If we got success, check the error
                // bits for a cal failure. We'll return the proper ReturnCode so all we need to do is FAPI_TRY.
                FAPI_TRY( mss::ccs::execute(i_target, l_program, p) );
                FAPI_TRY( mss::process_initial_cal_errors(p) );
            }
        }

    fapi_try_exit:
        FAPI_INF("End draminit training");
        return fapi2::current_err;
    }
}
<commit_msg>Change draminit_mc mcbist subtest to perform compares rather than ECC<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_draminit_training.C
/// @brief Train dram
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>

#include <p9_mss_draminit_training.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

extern "C"
{
    ///
    /// @brief Train dram
    /// @param[in] i_target, the McBIST of the ports of the dram you're training
    /// @param[in] i_special_training, optional CAL_STEP_ENABLE override. Used in sim, debug
    /// @return FAPI2_RC_SUCCESS iff ok
    ///
    fapi2::ReturnCode p9_mss_draminit_training( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
            const uint16_t i_special_training )
    {
        fapi2::buffer<uint16_t> l_cal_steps_enabled = i_special_training;

        FAPI_INF("Start draminit training");

        uint8_t l_reset_disable = 0;
        FAPI_TRY( mss::draminit_reset_disable(l_reset_disable) );

        // Configure the CCS engine.
        {
            fapi2::buffer<uint64_t> l_ccs_config;

            FAPI_TRY( mss::ccs::read_mode(i_target, l_ccs_config) );

            // It's unclear if we want to run with this true or false. Right now (10/15) this
            // has to be false. Shelton was unclear if this should be on or off in general BRS
            mss::ccs::stop_on_err(i_target, l_ccs_config, false);
            mss::ccs::ue_disable(i_target, l_ccs_config, false);
            mss::ccs::copy_cke_to_spare_cke(i_target, l_ccs_config, true);

            // Hm. Centaur sets this up for the longest duration possible. Can we do better?
            mss::ccs::cal_count(i_target, l_ccs_config, ~0, ~0);

#ifndef JIM_SAYS_TURN_OFF_ECC
            mss::ccs::disable_ecc(i_target, l_ccs_config);
#endif
            FAPI_TRY( mss::ccs::write_mode(i_target, l_ccs_config) );
        }

        // Clean out any previous calibration results, set bad-bits and configure the ranks.
        FAPI_DBG("MCA's on this McBIST: %d", i_target.getChildren<TARGET_TYPE_MCA>().size());

        for( auto p : i_target.getChildren<TARGET_TYPE_MCA>())
        {
            mss::ccs::program<TARGET_TYPE_MCBIST, TARGET_TYPE_MCA> l_program;

            // Setup a series of register probes which we'll see during the polling loop
            // Leaving these probes in here as we need them from time to time, but they
            // take up a lot of sim time, so we like to remove them simply
#ifdef TRAINING_POLLING_PROBES
            l_program.iv_probes =
            {
                // One block for each DP16
                {p, "wr_cntr_status0 (dp16 0)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_0},
                {p, "wr_cntr_status1 (dp16 0)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_0},
                {p, "wr_cntr_status2 (dp16 0)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_0},
                {p, "wr_lvl_status (dp16 0)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_0},

                {p, "wr_cntr_status0 (dp16 1)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_1},
                {p, "wr_cntr_status1 (dp16 1)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_1},
                {p, "wr_cntr_status2 (dp16 1)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_1},
                {p, "wr_lvl_status (dp16 1)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_1},

                {p, "wr_cntr_status0 (dp16 2)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_2},
                {p, "wr_cntr_status1 (dp16 2)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_2},
                {p, "wr_cntr_status2 (dp16 2)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_2},
                {p, "wr_lvl_status (dp16 2)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_2},

                {p, "wr_cntr_status0 (dp16 3)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_3},
                {p, "wr_cntr_status1 (dp16 3)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_3},
                {p, "wr_cntr_status2 (dp16 3)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_3},
                {p, "wr_lvl_status (dp16 3)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_3},

                {p, "wr_cntr_status0 (dp16 4)", MCA_DDRPHY_DP16_WR_CNTR_STATUS0_P0_4},
                {p, "wr_cntr_status1 (dp16 4)", MCA_DDRPHY_DP16_WR_CNTR_STATUS1_P0_4},
                {p, "wr_cntr_status2 (dp16 4)", MCA_DDRPHY_DP16_WR_CNTR_STATUS2_P0_4},
                {p, "wr_lvl_status (dp16 4)",   MCA_DDRPHY_DP16_WR_LVL_STATUS0_P0_4},
            };
#endif
            // Delays in the CCS instruction ARR1 for training are supposed to be 0xFFFF,
            // and we're supposed to poll for the done or timeout bit. But we don't want
            // to wait 0xFFFF cycles before we start polling - that's too long. So we put
            // in a best-guess of how long to wait. This, in a perfect world, would be the
            // time it takes one rank to train one training algorithm times the number of
            // ranks we're going to train. We fail-safe as worst-case we simply poll the
            // register too much - so we can tune this as we learn more.
            l_program.iv_poll.iv_initial_sim_delay = mss::DELAY_100US;
            l_program.iv_poll.iv_initial_sim_delay = 200;
            l_program.iv_poll.iv_poll_count = 0xFFFF;

            // Returned from set_rank_pairs, it tells us how many rank pairs
            // we configured on this port.
            std::vector<uint64_t> l_pairs;

#ifdef CAL_STATUS_DOESNT_REPORT_COMPLETE
            // This isn't correct - shouldn't be setting
            static const uint64_t CLEAR_CAL_COMPLETE = 0x000000000000F000;
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_STATUS_P0, CLEAR_CAL_COMPLETE) );
#endif
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_ERROR_P0, 0) );
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0, 0) );

            // Disable port fails as it doesn't appear the MC handles initial cal timeouts
            // correctly (cal_length.) BRS, see conversation with Brad Michael
            FAPI_TRY( mss::change_port_fail_disable(p, mss::ON ) );

            // The following registers must be configured to the correct operating environment:

            // Unclear, can probably be 0's for sim BRS
            // • Section 5.2.5.10 SEQ ODT Write Configuration {0-3} on page 422

            FAPI_TRY( mss::reset_seq_config0(p) );
            FAPI_TRY( mss::reset_seq_rd_wr_data(p) );

            FAPI_TRY( mss::reset_odt_config(p) );

            // These are reset in phy_scominit
            // • Section 5.2.6.1 WC Configuration 0 Register on page 434
            // • Section 5.2.6.2 WC Configuration 1 Register on page 436
            // • Section 5.2.6.3 WC Configuration 2 Register on page 438

            // Get our rank pairs.
            FAPI_TRY( mss::get_rank_pairs(p, l_pairs) );

            // Setup the config register
            //
            // Grab the attribute which contains the information on what cal steps we should run
            // if the i_specal_training bits have not been specified.
            if (i_special_training == 0)
            {
                FAPI_TRY( mss::cal_step_enable(p, l_cal_steps_enabled) );
            }

            FAPI_DBG("cal steps enabled: 0x%x special training: 0x%x", l_cal_steps_enabled, i_special_training);

            // Check to see if we're supposed to reset the delay values before starting training
            // don't reset if we're running special training - assumes there's a checkpoint which has valid state.
            if ((l_reset_disable == fapi2::ENUM_ATTR_MSS_DRAMINIT_RESET_DISABLE_ENABLE) && (i_special_training == 0))
            {
                FAPI_TRY( mss::dp16<TARGET_TYPE_MCA>().reset_delay_values(p, l_pairs) );
            }

            FAPI_DBG("generating calibration CCS instructions: %d rank-pairs", l_pairs.size());

            // For each rank pair we need to calibrate, pop a ccs instruction in an array and execute it.
            // NOTE: IF YOU CALIBRATE MORE THAN ONE RANK PAIR PER CCS PROGRAM, MAKE SURE TO CHANGE
            // THE PROCESSING OF THE ERRORS. (it's hard to figure out which DIMM failed, too) BRS.
            for (auto rp : l_pairs)
            {
                auto l_inst = mss::ccs::initial_cal_command<TARGET_TYPE_MCBIST>(rp);

                FAPI_DBG("exeecuting training CCS instruction: 0x%llx, 0x%llx", l_inst.arr0, l_inst.arr1);
                l_program.iv_instructions.push_back(l_inst);

                // We need to figure out how long to wait before we start polling. Each cal step has an expected
                // duration, so for each cal step which was enabled, we update the CCS program.
                FAPI_TRY( mss::cal_timer_setup(p, l_program.iv_poll, l_cal_steps_enabled) );
                FAPI_TRY( mss::setup_cal_config(p, rp, l_cal_steps_enabled) );

                // In the event of an init cal hang, CCS_STATQ(2) will assert and CCS_STATQ(3:5) = “001” to indicate a
                // timeout. Otherwise, if calibration completes, FW should inspect DDRPHY_FIR_REG bits (50) and (58)
                // for signs of a calibration error. If either bit is on, then the DDRPHY_PC_INIT_CAL_ERROR register
                // should be polled to determine which calibration step failed.

                // If we got a cal timeout, or another CCS error just leave now. If we got success, check the error
                // bits for a cal failure. We'll return the proper ReturnCode so all we need to do is FAPI_TRY.
                FAPI_TRY( mss::ccs::execute(i_target, l_program, p) );
                FAPI_TRY( mss::process_initial_cal_errors(p) );
            }
        }

    fapi_try_exit:
        FAPI_INF("End draminit training");
        return fapi2::current_err;
    }
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_draminit_training.C
/// @brief Train dram
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>

#include <p9_mss_draminit_training.H>
#include <lib/utils/count_dimm.H>
#include <lib/shared/mss_const.H>
#include <lib/workarounds/dp16_workarounds.H>
#include <lib/fir/unmask.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

extern "C"
{
    ///
    /// @brief Train dram
    /// @param[in] i_target, the McBIST of the ports of the dram you're training
    /// @param[in] i_special_training, optional CAL_STEP_ENABLE override. Used in sim, debug
    /// @param[in] i_abort_on_error, optional CAL_ABORT_ON_ERROR override. Used in sim, debug
    /// @return FAPI2_RC_SUCCESS iff ok
    ///
    fapi2::ReturnCode p9_mss_draminit_training( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
            const uint16_t i_special_training,
            const uint8_t i_abort_on_error)
    {
        // Keep track of the last error seen by a port
        fapi2::ReturnCode l_port_error = fapi2::FAPI2_RC_SUCCESS;
        fapi2::buffer<uint16_t> l_cal_steps_enabled = i_special_training;

        FAPI_INF("Start draminit training");

        // If there are no DIMM we don't need to bother. In fact, we can't as we didn't setup
        // attributes for the PHY, etc.
        if (mss::count_dimm(i_target) == 0)
        {
            FAPI_INF("... skipping draminit_training %s - no DIMM ...", mss::c_str(i_target));
            return fapi2::FAPI2_RC_SUCCESS;
        }

        uint8_t l_reset_disable = 0;
        FAPI_TRY( mss::mrw_reset_delay_before_cal(l_reset_disable) );

        // Configure the CCS engine.
        {
            fapi2::buffer<uint64_t> l_ccs_config;

            FAPI_TRY( mss::ccs::read_mode(i_target, l_ccs_config) );

            // It's unclear if we want to run with this true or false. Right now (10/15) this
            // has to be false. Shelton was unclear if this should be on or off in general BRS
            mss::ccs::stop_on_err(i_target, l_ccs_config, mss::LOW);
            mss::ccs::ue_disable(i_target, l_ccs_config, mss::LOW);
            mss::ccs::copy_cke_to_spare_cke(i_target, l_ccs_config, mss::HIGH);
            mss::ccs::parity_after_cmd(i_target, l_ccs_config, mss::HIGH);

            // Hm. Centaur sets this up for the longest duration possible. Can we do better?
            mss::ccs::cal_count(i_target, l_ccs_config, ~0, ~0);
            FAPI_TRY( mss::ccs::write_mode(i_target, l_ccs_config) );
        }

        // Clean out any previous calibration results, set bad-bits and configure the ranks.
        FAPI_DBG("%s MCA's on this McBIST: %d", mss::c_str(i_target), mss::find_targets<TARGET_TYPE_MCA>(i_target).size());

        for( const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
        {
            // Keep track of the last error seen by a rank pair
            fapi2::ReturnCode l_rank_pair_error = fapi2::FAPI2_RC_SUCCESS;

            // Returned from set_rank_pairs, it tells us how many rank pairs
            // we configured on this port.
            std::vector<uint64_t> l_pairs;

            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_ERROR_P0, 0) );
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0, 0) );

            // Disable port fails as it doesn't appear the MC handles initial cal timeouts
            // correctly (cal_length.) BRS, see conversation with Brad Michael
            FAPI_TRY( mss::change_port_fail_disable(p, mss::ON ) );

            // The following registers must be configured to the correct operating environment:

            // These are reset in phy_scominit
            // Section 5.2.5.10 SEQ ODT Write Configuration {0-3} on page 422
            // Section 5.2.6.1 WC Configuration 0 Register on page 434
            // Section 5.2.6.2 WC Configuration 1 Register on page 436
            // Section 5.2.6.3 WC Configuration 2 Register on page 438

            // Get our rank pairs.
            FAPI_TRY( mss::rank::get_rank_pairs(p, l_pairs) );

            // Setup the config register
            //
            // Grab the attribute which contains the information on what cal steps we should run
            // if the i_specal_training bits have not been specified.
            // TODO RTC:166422 update training code to set cal step enable and consume it everywhere locally
            if (i_special_training == 0)
            {
                FAPI_TRY( mss::cal_step_enable(p, l_cal_steps_enabled) );
            }

            FAPI_DBG("cal steps enabled: 0x%x special training: 0x%x", l_cal_steps_enabled, i_special_training);

            // Check to see if we're supposed to reset the delay values before starting training
            // don't reset if we're running special training - assumes there's a checkpoint which has valid state.
            if ((l_reset_disable == fapi2::ENUM_ATTR_MSS_MRW_RESET_DELAY_BEFORE_CAL_YES) && (i_special_training == 0))
            {
                FAPI_INF("resetting delay values before cal %s", mss::c_str(p));
                FAPI_TRY( mss::dp16::reset_delay_values(p, l_pairs) );
            }

            FAPI_DBG("generating calibration CCS instructions: %d rank-pairs", l_pairs.size());

            // For each rank pair we need to calibrate, pop a ccs instruction in an array and execute it.
            // NOTE: IF YOU CALIBRATE MORE THAN ONE RANK PAIR PER CCS PROGRAM, MAKE SURE TO CHANGE
            // THE PROCESSING OF THE ERRORS. (it's hard to figure out which DIMM failed, too) BRS.
            for (const auto& rp : l_pairs)
            {
                uint8_t cal_abort_on_error = i_abort_on_error;

                if (i_abort_on_error == CAL_ABORT_SENTINAL)
                {
                    FAPI_TRY( mss::cal_abort_on_error(cal_abort_on_error) );
                }

                // Execute selected cal steps
                FAPI_TRY( mss::setup_and_execute_cal(p, rp, l_cal_steps_enabled, i_abort_on_error) );

                // Conducts workarounds after training if needed
                FAPI_TRY( mss::workarounds::dp16::post_training_workarounds( p, l_cal_steps_enabled ) );

                // If we're aborting on error we can just FAPI_TRY. If we're not, we don't want to exit if there's
                // an error but we want to log the error and keep on keeping on.
                if ((fapi2::current_err = mss::process_initial_cal_errors(p)) != fapi2::FAPI2_RC_SUCCESS)
                {
                    fapi2::logError(fapi2::current_err);

                    if (cal_abort_on_error)
                    {
                        goto fapi_try_exit;
                    }

                    // Keep tack of the last cal error we saw.
                    l_rank_pair_error = fapi2::current_err;
                }
            }

            // Once we've trained all the rank pairs we can record the bad bits in the attributes if we have an error
            // This error is the most recent error seen on a port, too, so we keep track of that.
            if (l_rank_pair_error != fapi2::FAPI2_RC_SUCCESS)
            {
                FAPI_TRY( mss::dp16::record_bad_bits(p) );
                l_port_error = l_rank_pair_error;
            }
        }

        // So we're calibrated the entire port. If we're here either we didn't have any errors or the last error
        // seen on a port is the error for this entire controller.
        FAPI_TRY(l_port_error, "Seeing port error, exiting training");

        // Unmask FIR
        FAPI_TRY( mss::unmask::after_draminit_training(i_target) );

    fapi_try_exit:
        FAPI_INF("End draminit training");
        return fapi2::current_err;
    }
}
<commit_msg>Remove ZQCAL redundant CCS inst, move to draminit_training<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_draminit_training.C
/// @brief Train dram
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>

#include <p9_mss_draminit_training.H>
#include <lib/utils/count_dimm.H>
#include <lib/shared/mss_const.H>
#include <lib/workarounds/dp16_workarounds.H>
#include <lib/fir/unmask.H>
#include <lib/dimm/ddr4/zqcal.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

extern "C"
{
    ///
    /// @brief Train dram
    /// @param[in] i_target, the McBIST of the ports of the dram you're training
    /// @param[in] i_special_training, optional CAL_STEP_ENABLE override. Used in sim, debug
    /// @param[in] i_abort_on_error, optional CAL_ABORT_ON_ERROR override. Used in sim, debug
    /// @return FAPI2_RC_SUCCESS iff ok
    ///
    fapi2::ReturnCode p9_mss_draminit_training( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
            const uint32_t i_special_training,
            const uint8_t i_abort_on_error)
    {
        // Keep track of the last error seen by a port
        fapi2::ReturnCode l_port_error = fapi2::FAPI2_RC_SUCCESS;
        fapi2::buffer<uint32_t> l_cal_steps_enabled = i_special_training;

        FAPI_INF("Start draminit training");

        // If there are no DIMM we don't need to bother. In fact, we can't as we didn't setup
        // attributes for the PHY, etc.
        if (mss::count_dimm(i_target) == 0)
        {
            FAPI_INF("... skipping draminit_training %s - no DIMM ...", mss::c_str(i_target));
            return fapi2::FAPI2_RC_SUCCESS;
        }

        uint8_t l_reset_disable = 0;
        FAPI_TRY( mss::mrw_reset_delay_before_cal(l_reset_disable) );

        // Configure the CCS engine.
        {
            fapi2::buffer<uint64_t> l_ccs_config;

            FAPI_TRY( mss::ccs::read_mode(i_target, l_ccs_config) );

            // It's unclear if we want to run with this true or false. Right now (10/15) this
            // has to be false. Shelton was unclear if this should be on or off in general BRS
            mss::ccs::stop_on_err(i_target, l_ccs_config, mss::LOW);
            mss::ccs::ue_disable(i_target, l_ccs_config, mss::LOW);
            mss::ccs::copy_cke_to_spare_cke(i_target, l_ccs_config, mss::HIGH);
            mss::ccs::parity_after_cmd(i_target, l_ccs_config, mss::HIGH);

            // Hm. Centaur sets this up for the longest duration possible. Can we do better?
            mss::ccs::cal_count(i_target, l_ccs_config, ~0, ~0);
            FAPI_TRY( mss::ccs::write_mode(i_target, l_ccs_config) );
        }

        // Clean out any previous calibration results, set bad-bits and configure the ranks.
        FAPI_DBG("%s MCA's on this McBIST: %d", mss::c_str(i_target), mss::find_targets<TARGET_TYPE_MCA>(i_target).size());

        for( const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
        {
            // Keep track of the last error seen by a rank pair
            fapi2::ReturnCode l_rank_pair_error(fapi2::FAPI2_RC_SUCCESS);

            // Returned from set_rank_pairs, it tells us how many rank pairs
            // we configured on this port.
            std::vector<uint64_t> l_pairs;

            // Grab the attribute which contains the information on what cal steps we should run
            // if the i_specal_training bits have not been specified.
            if (i_special_training == 0)
            {
                FAPI_TRY( mss::cal_step_enable(p, l_cal_steps_enabled) );
            }

            FAPI_DBG("cal steps enabled: 0x%x special training: 0x%x", l_cal_steps_enabled, i_special_training);

            // ZQCAL (for DRAMs and LRDIMM data buffers) isn't a PHY calibration,
            // so we don't add it in the PHY calibration setup and do it separately here.
            FAPI_TRY( mss::setup_and_execute_zqcal(p, l_cal_steps_enabled) );

            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_ERROR_P0, 0) );
            FAPI_TRY( mss::putScom(p, MCA_DDRPHY_PC_INIT_CAL_CONFIG0_P0, 0) );

            // Disable port fails as it doesn't appear the MC handles initial cal timeouts
            // correctly (cal_length.) BRS, see conversation with Brad Michael
            FAPI_TRY( mss::change_port_fail_disable(p, mss::ON ) );

            // The following registers must be configured to the correct operating environment:

            // These are reset in phy_scominit
            // Section 5.2.5.10 SEQ ODT Write Configuration {0-3} on page 422
            // Section 5.2.6.1 WC Configuration 0 Register on page 434
            // Section 5.2.6.2 WC Configuration 1 Register on page 436
            // Section 5.2.6.3 WC Configuration 2 Register on page 438

            // Get our rank pairs.
            FAPI_TRY( mss::rank::get_rank_pairs(p, l_pairs) );

            // Setup the config register

            // don't reset if we're running special training - assumes there's a checkpoint which has valid state.
            if ((l_reset_disable == fapi2::ENUM_ATTR_MSS_MRW_RESET_DELAY_BEFORE_CAL_YES) && (i_special_training == 0))
            {
                FAPI_INF("resetting delay values before cal %s", mss::c_str(p));
                FAPI_TRY( mss::dp16::reset_delay_values(p, l_pairs) );
            }

            FAPI_DBG("generating calibration CCS instructions: %d rank-pairs", l_pairs.size());

            // For each rank pair we need to calibrate, pop a ccs instruction in an array and execute it.
            // NOTE: IF YOU CALIBRATE MORE THAN ONE RANK PAIR PER CCS PROGRAM, MAKE SURE TO CHANGE
            // THE PROCESSING OF THE ERRORS. (it's hard to figure out which DIMM failed, too) BRS.
            for (const auto& rp : l_pairs)
            {
                uint8_t l_cal_abort_on_error = i_abort_on_error;

                if (i_abort_on_error == CAL_ABORT_SENTINAL)
                {
                    FAPI_TRY( mss::cal_abort_on_error(l_cal_abort_on_error) );
                }

                // Execute selected cal steps
                FAPI_TRY( mss::setup_and_execute_cal(p, rp, l_cal_steps_enabled, i_abort_on_error) );

                // If we're aborting on error we can just FAPI_TRY. If we're not, we don't want to exit if there's
                // an error but we want to log the error and keep on keeping on.
                if ((fapi2::current_err = mss::process_initial_cal_errors(p)) != fapi2::FAPI2_RC_SUCCESS)
                {
                    fapi2::logError(fapi2::current_err);

                    if (l_cal_abort_on_error)
                    {
                        goto fapi_try_exit;
                    }

                    // Keep tack of the last cal error we saw.
                    l_rank_pair_error = fapi2::current_err;
                }
            }// rank pairs

            // Conducts workarounds after training if needed
            FAPI_TRY( mss::workarounds::dp16::post_training_workarounds( p, l_cal_steps_enabled ) );

            // Once we've trained all the rank pairs we can record the bad bits in the attributes if we have an error
            // This error is the most recent error seen on a port, too, so we keep track of that.
            if (l_rank_pair_error != fapi2::FAPI2_RC_SUCCESS)
            {
                FAPI_TRY( mss::dp16::record_bad_bits(p) );
                l_port_error = l_rank_pair_error;
            }
        }

        // So we're calibrated the entire port. If we're here either we didn't have any errors or the last error
        // seen on a port is the error for this entire controller.
        FAPI_TRY(l_port_error, "Seeing port error, exiting training");

        // Unmask FIR
        FAPI_TRY( mss::unmask::after_draminit_training(i_target) );

    fapi_try_exit:
        FAPI_INF("End draminit training");
        return fapi2::current_err;
    }
}
<|endoftext|>