Skip to content
Snippets Groups Projects
FirstOrderAssembler.cc 12.9 KiB
Newer Older
//
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology 
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.


#include <boost/numeric/mtl/mtl.hpp>
#include "Assembler.h"
#include "FirstOrderAssembler.h"
#include "Operator.h"
#include "QPsiPhi.h"
#include "FiniteElemSpace.h"
#include "Quadrature.h"
#include "DOFVector.h"

namespace AMDiS {

  std::vector<SubAssembler*> FirstOrderAssembler::optimizedSubAssemblersGrdPhi;
  std::vector<SubAssembler*> FirstOrderAssembler::optimizedSubAssemblersGrdPsi;

  std::vector<SubAssembler*> FirstOrderAssembler::standardSubAssemblersGrdPhi;
  std::vector<SubAssembler*> FirstOrderAssembler::standardSubAssemblersGrdPsi;


  FirstOrderAssembler::FirstOrderAssembler(Operator *op,
					   Assembler *assembler,
					   Quadrature *quad,
					   bool optimized,
					   FirstOrderType type)
    : SubAssembler(op, assembler, quad, 1, optimized, type)
    FUNCNAME("FirstOrderAssmebler::FirstOrderAssembler()");
    
    TEST_EXIT_DBG(dim > 0)("Should not happen!\n");

    Lb.resize(1);
    Lb[0].change_dim(dim + 1);

  FirstOrderAssembler* FirstOrderAssembler::getSubAssembler(Operator* op,
							    Assembler *assembler,
							    Quadrature *quad,
							    FirstOrderType type,
							    bool optimized)
  {
    std::vector<SubAssembler*> *subAssemblers =
      optimized ?
      (type == GRD_PSI ? 
       &optimizedSubAssemblersGrdPsi : 
       &optimizedSubAssemblersGrdPhi) :
      (type == GRD_PSI ? 
       &standardSubAssemblersGrdPsi :
       &standardSubAssemblersGrdPhi);
    
Thomas Witkowski's avatar
Thomas Witkowski committed
    std::vector<OperatorTerm*> opTerms = 
      (type == GRD_PSI) ? op->firstOrderGrdPsi : op->firstOrderGrdPhi;

    // check if a assembler is needed at all
      return NULL;

    sort(opTerms.begin(), opTerms.end());

    FirstOrderAssembler *newAssembler;

    // check if a new assembler is needed
    for (unsigned int i = 0; i < subAssemblers->size(); i++) {
      std::vector<OperatorTerm*> assTerms = *((*subAssemblers)[i]->getTerms());
    
      sort(assTerms.begin(), assTerms.end());   

      if (opTerms == assTerms && (*subAssemblers)[i]->getQuadrature() == quad)
	return dynamic_cast<FirstOrderAssembler*>((*subAssemblers)[i]);
    }

    // check if all terms are pw_const
    bool pwConst = true;
    for (unsigned int i = 0; i < opTerms.size(); i++) {
      if (!(opTerms[i])->isPWConst()) {
	pwConst = false;
	break;
      }
    }  

    // create new assembler
      newAssembler = 
	(type == GRD_PSI) ?
Thomas Witkowski's avatar
Thomas Witkowski committed
	dynamic_cast<FirstOrderAssembler*>(new Stand10(op, assembler, quad)) :
	dynamic_cast<FirstOrderAssembler*>(new Stand01(op, assembler, quad));    
	 newAssembler = 
	   (type == GRD_PSI) ?
	   dynamic_cast<FirstOrderAssembler*>(new Pre10(op, assembler, quad)) :
	   dynamic_cast<FirstOrderAssembler*>(new Pre01(op, assembler, quad));
	 newAssembler = 
	   (type == GRD_PSI) ?
	   dynamic_cast<FirstOrderAssembler*>(new Quad10(op, assembler, quad)) :
	   dynamic_cast<FirstOrderAssembler*>(new Quad01(op, assembler, quad));

    subAssemblers->push_back(newAssembler);
    return newAssembler;
  Stand10::Stand10(Operator *op, Assembler *assembler, Quadrature *quad) 
    : FirstOrderAssembler(op, assembler, quad, false, GRD_PSI)
    name = "standard first order assembler";

    psi = rowFeSpace->getBasisFcts();
    phi = colFeSpace->getBasisFcts();
  void Stand10::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
    mtl::dense_vector<double> grdPsi(dim + 1, 0.0);
    int nPoints = quadrature->getNumPoints();
    Lb.resize(nPoints);
    std::vector<double> phival(nCol);
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq].change_dim(dim + 1);
      Lb[iq] = 0.0;
    }
    for (unsigned int i = 0; i < terms.size(); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
  
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq] *= elInfo->getDet();

      for (int i = 0; i < nCol; i++)
	phival[i] = (*(phi->getPhi(i)))(quadrature->getLambda(iq));      

      for (int i = 0; i < nRow; i++) {
	(*(psi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPsi);
	for (int j = 0; j < nCol; j++)
	  mat[i][j] += quadrature->getWeight(iq) * phival[j] * dot(Lb[iq], grdPsi);
  void Stand10::calculateElementVector(const ElInfo *elInfo, ElementVector& vec)
    mtl::dense_vector<double> grdPsi(dim + 1, 0.0);
    int nPoints = quadrature->getNumPoints();
    Lb.resize(nPoints);

    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq].change_dim(dim + 1);
      Lb[iq] = 0.0;
    }

    for (unsigned int i = 0; i < terms.size(); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
  
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq] *= elInfo->getDet();

      for (int i = 0; i < nRow; i++) {
	(*(psi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPsi);
	vec[i] += quadrature->getWeight(iq) * dot(Lb[iq], grdPsi);

  Quad10::Quad10(Operator *op, Assembler *assembler, Quadrature *quad) 
    : FirstOrderAssembler(op, assembler, quad, true, GRD_PSI)
  {
    name = "fast quadrature first order assembler";
  }
  void Quad10::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
      const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
      psiFast = updateFastQuadrature(psiFast, basFcts, INIT_GRD_PHI);
      basFcts = colFeSpace->getBasisFcts();
      phiFast = updateFastQuadrature(phiFast, basFcts, INIT_PHI);
      firstCall = false;
    }

    int nPoints = quadrature->getNumPoints();
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq].change_dim(dim + 1);
      Lb[iq] = 0.0;
    }
    for (unsigned int i = 0; i < terms.size(); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);

    const mtl::dense2D<double>& phi = phiFast->getPhi();

    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq] *= elInfo->getDet();

      const vector<mtl::dense_vector<double> >& grdPsi = psiFast->getGradient(iq);
      double factor = quadrature->getWeight(iq);
      for (int i = 0; i < nRow; i++) {
	for (int j = 0; j < nCol; j++)
	  mat[i][j] += factor * phi[iq][j] * dot(Lb[iq], grdPsi[i]);
  void Quad10::calculateElementVector(const ElInfo *elInfo, ElementVector& vec)
      const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
      psiFast = updateFastQuadrature(psiFast, basFcts, INIT_GRD_PHI);
      basFcts = colFeSpace->getBasisFcts();
      phiFast = updateFastQuadrature(phiFast, basFcts, INIT_PHI);
      firstCall = false;
    }

    int nPoints = quadrature->getNumPoints();
    Lb.resize(nPoints);
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq].change_dim(dim + 1);
      Lb[iq] = 0.0;
    }
    for (unsigned int i = 0; i < terms.size(); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
  
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq] *= elInfo->getDet();
      const vector<mtl::dense_vector<double> >& grdPsi = psiFast->getGradient(iq);
Thomas Witkowski's avatar
Thomas Witkowski committed
      for (int i = 0; i < nRow; i++)
	vec[i] += quadrature->getWeight(iq) * dot(Lb[iq], grdPsi[i]);
  Pre10::Pre10(Operator *op, Assembler *assembler, Quadrature *quad) 
    : FirstOrderAssembler(op, assembler, quad, true, GRD_PSI)
  {
    name = "precalculated first order assembler";
  void Pre10::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
  {
    const int *k;
    const double *values;

    if (firstCall) {
      q10 = Q10PsiPhi::provideQ10PsiPhi(rowFeSpace->getBasisFcts(), 
					colFeSpace->getBasisFcts(), 
					quadrature);
      q1 = Q1Psi::provideQ1Psi(rowFeSpace->getBasisFcts(), quadrature);
      firstCall = false;    
    }

    const int **nEntries = q10->getNumberEntries();
    // Do not need do resize Lb, because it's size is always at least one.
    for (unsigned int i = 0; i < terms.size(); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);

    Lb[0] *= elInfo->getDet();

    for (int i = 0; i < nRow; i++) {
      for (int j = 0; j < nCol; j++) {
	k = q10->getKVec(i, j);
	values = q10->getValVec(i, j);
	double val = 0.0;
	for (int m = 0; m < nEntries[i][j]; m++)
	  val += values[m] * Lb[0][k[m]];	
  Stand01::Stand01(Operator *op, Assembler *assembler, Quadrature *quad) 
    : FirstOrderAssembler(op, assembler, quad, false, GRD_PHI)
    FUNCNAME("Stand01::Stand01()");

    TEST_EXIT_DBG(dim > 0)("Should not happen!\n");

    grdPhi.resize(nCol);
    for (int i = 0; i < nCol; i++)
      grdPhi[i].change_dim(dim + 1);
    psi = rowFeSpace->getBasisFcts();
    phi = colFeSpace->getBasisFcts();
  void Stand01::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
  {
    int nPoints = quadrature->getNumPoints();
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq].change_dim(dim + 1);
      Lb[iq] = 0.0;
    }
    for (int i = 0; i < static_cast<int>(terms.size()); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
  
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq] *= elInfo->getDet();

      for (int i = 0; i < nCol; i++)
	(*(phi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPhi[i]);

      for (int i = 0; i < nRow; i++) {
	double psival = (*(psi->getPhi(i)))(quadrature->getLambda(iq));
	for (int j = 0; j < nCol; j++)
	  mat[i][j] += quadrature->getWeight(iq) * psival * dot(Lb[iq], grdPhi[j]);
  Quad01::Quad01(Operator *op, Assembler *assembler, Quadrature *quad) 
    : FirstOrderAssembler(op, assembler, quad, true, GRD_PHI)
  {
    name = "fast quadrature first order assembler";
  }

  void Quad01::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
      const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
      psiFast = updateFastQuadrature(psiFast, basFcts, INIT_PHI);
      basFcts = colFeSpace->getBasisFcts();
      phiFast = updateFastQuadrature(phiFast, basFcts, INIT_GRD_PHI);
      firstCall = false;      
    }

    int nPoints = quadrature->getNumPoints();
    for (int iq = 0; iq < nPoints; iq++) {
      Lb[iq].change_dim(dim + 1);
      Lb[iq] = 0.0;
    }
    for (int i = 0; i < static_cast<int>(terms.size()); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
    const mtl::dense2D<double>& psi = psiFast->getPhi();
    mtl::dense2D<double> facMat(nPoints, nCol);
    for (int iq = 0; iq < nPoints; iq++) {
      double weight = quadrature->getWeight(iq);
      mtl::dense_vector<double>& Lb_iq = Lb[iq];
      const vector<mtl::dense_vector<double> >& grdPsi = phiFast->getGradient(iq);
      Lb_iq *= elInfo->getDet();

      for (int i = 0; i < nCol; i++)
	facMat[iq][i] = weight * dot(Lb_iq, grdPsi[i]);
  Pre01::Pre01(Operator *op, Assembler *assembler, Quadrature *quad) 
    : FirstOrderAssembler(op, assembler, quad, true, GRD_PHI)
  {
    name = "precalculated first order assembler";
  }

  void Pre01::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
  {
    const int *l;
    const double *values;

    if (firstCall) {
      q01 = Q01PsiPhi::provideQ01PsiPhi(rowFeSpace->getBasisFcts(), 
					colFeSpace->getBasisFcts(), 
					quadrature);
      q1 = Q1Psi::provideQ1Psi(rowFeSpace->getBasisFcts(), quadrature);
      firstCall = false;
    }

    const int **nEntries = q01->getNumberEntries();
    // Do not need to resize Lb, because it's size is always at least one!
    for (int i = 0; i < static_cast<int>( terms.size()); i++)
      (static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);

    Lb[0] *= elInfo->getDet();

    for (int i = 0; i < nRow; i++) {
      for (int j = 0; j < nCol; j++) {
	l = q01->getLVec(i, j);
	values = q01->getValVec(i, j);
	double val = 0.0;
	for (int m = 0; m < nEntries[i][j]; m++) {
	  val += values[m] * Lb[0][l[m]];
	}
  void Pre10::calculateElementVector(const ElInfo *elInfo, ElementVector& vec)
  {
    const int *k;
    const double *values;

    if (firstCall) {
      q10 = Q10PsiPhi::provideQ10PsiPhi(rowFeSpace->getBasisFcts(), 
					colFeSpace->getBasisFcts(), 
					quadrature);
      q1 = Q1Psi::provideQ1Psi(rowFeSpace->getBasisFcts(), quadrature);
      firstCall = false;      
    }

    const int *nEntries = q1->getNumberEntries();
    // Do not need to resize Lb, because it's size is always at least one!
    for (int i = 0; i < static_cast<int>(terms.size()); i++)
      (static_cast<FirstOrderTerm*>(terms[i]))->getLb(elInfo, Lb);

    Lb[0] *= elInfo->getDet();

    for (int i = 0; i < nRow; i++) {
      k = q1->getKVec(i);
      values = q1->getValVec(i);
      double val = 0.0;
      for (int m = 0; m < nEntries[i]; m++) {
	val += values[m] * Lb[0][k[m]];
      }