Files
mfem/linalg/complex_operator.cpp
T

188 lines
4.8 KiB
C++

// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.
#include "complex_operator.hpp"
namespace mfem
{
ComplexOperator::ComplexOperator(Operator * Op_Real, Operator * Op_Imag,
bool ownReal, bool ownImag,
Convention convention)
: Operator(2*Op_Real->Height(), 2*Op_Real->Width())
, Op_Real_(Op_Real)
, Op_Imag_(Op_Imag)
, ownReal_(ownReal)
, ownImag_(ownImag)
, convention_(convention)
, x_r_(NULL, Op_Real->Width())
, x_i_(NULL, Op_Real->Width())
, y_r_(NULL, Op_Real->Height())
, y_i_(NULL, Op_Real->Height())
, u_(NULL)
, v_(NULL)
{}
ComplexOperator::~ComplexOperator()
{
if (ownReal_) { delete Op_Real_; }
if (ownImag_) { delete Op_Imag_; }
delete u_;
delete v_;
}
void ComplexOperator::Mult(const Vector &x, Vector &y) const
{
double * x_data = x.GetData();
x_r_.SetData(x_data);
x_i_.SetData(&x_data[Op_Real_->Width()]);
y_r_.SetData(&y[0]);
y_i_.SetData(&y[Op_Real_->Height()]);
this->Mult(x_r_, x_i_, y_r_, y_i_);
}
void ComplexOperator::Mult(const Vector &x_r, const Vector &x_i,
Vector &y_r, Vector &y_i) const
{
if (Op_Real_)
{
Op_Real_->Mult(x_r, y_r);
Op_Real_->Mult(x_i, y_i);
}
else
{
y_r = 0.0;
y_i = 0.0;
}
if (Op_Imag_)
{
if (!v_) { v_ = new Vector(Op_Imag_->Height()); }
Op_Imag_->Mult(x_i, *v_);
y_r_ -= *v_;
Op_Imag_->Mult(x_r, *v_);
y_i_ += *v_;
}
if (convention_ == BLOCK_SYMMETRIC)
{
y_i_ *= -1.0;
}
}
void ComplexOperator::MultTranspose(const Vector &x, Vector &y) const
{
double * x_data = x.GetData();
y_r_.SetData(x_data);
y_i_.SetData(&x_data[Op_Real_->Height()]);
x_r_.SetData(&y[0]);
x_i_.SetData(&y[Op_Real_->Width()]);
this->MultTranspose(y_r_, y_i_, x_r_, x_i_);
}
void ComplexOperator::MultTranspose(const Vector &x_r, const Vector &x_i,
Vector &y_r, Vector &y_i) const
{
if (Op_Real_)
{
Op_Real_->MultTranspose(x_r, y_r);
Op_Real_->MultTranspose(x_i, y_i);
if (convention_ == BLOCK_SYMMETRIC)
{
y_i *= -1.0;
}
}
else
{
y_r = 0.0;
y_i = 0.0;
}
if (Op_Imag_)
{
if (!u_) { u_ = new Vector(Op_Imag_->Width()); }
Op_Imag_->MultTranspose(x_i, *u_);
y_r_.Add(convention_ == BLOCK_SYMMETRIC ? -1.0 : 1.0, *u_);
Op_Imag_->MultTranspose(x_r, *u_);
y_i_ -= *u_;
}
}
SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const
{
SparseMatrix * A_r = dynamic_cast<SparseMatrix*>(Op_Real_);
SparseMatrix * A_i = dynamic_cast<SparseMatrix*>(Op_Imag_);
const int nrows_r = (A_r)?A_r->Height():0;
const int nrows_i = (A_i)?A_i->Height():0;
const int nrows = std::max(nrows_r, nrows_i);
const int *I_r = (A_r)?A_r->GetI():NULL;
const int *I_i = (A_i)?A_i->GetI():NULL;
const int *J_r = (A_r)?A_r->GetJ():NULL;
const int *J_i = (A_i)?A_i->GetJ():NULL;
const double *D_r = (A_r)?A_r->GetData():NULL;
const double *D_i = (A_i)?A_i->GetData():NULL;
const int nnz_r = (I_r)?I_r[nrows]:0;
const int nnz_i = (I_i)?I_i[nrows]:0;
const int nnz = 2 * (nnz_r + nnz_i);
int *I = new int[this->Height()+1];
int *J = new int[nnz];
double *D = new double[nnz];
const double factor = (convention_ == HERMITIAN) ? 1.0 : -1.0;
I[0] = 0;
I[nrows] = nnz_r + nnz_i;
for (int i=0; i<nrows; i++)
{
I[i + 1] = ((I_r)?I_r[i+1]:0) + ((I_i)?I_i[i+1]:0);
I[i + nrows + 1] = I[i+1] + nnz_r + nnz_i;
if (I_r)
{
const int off_i = (I_i)?(I_i[i+1] - I_i[i]):0;
for (int j=0; j<I_r[i+1] - I_r[i]; j++)
{
J[I[i] + j] = J_r[I_r[i] + j];
D[I[i] + j] = D_r[I_r[i] + j];
J[I[i+nrows] + off_i + j] = J_r[I_r[i] + j] + nrows;
D[I[i+nrows] + off_i + j] = factor*D_r[I_r[i] + j];
}
}
if (I_i)
{
const int off_r = (I_r)?(I_r[i+1] - I_r[i]):0;
for (int j=0; j<I_i[i+1] - I_i[i]; j++)
{
J[I[i] + off_r + j] = J_i[I_i[i] + j] + nrows;
D[I[i] + off_r + j] = -D_i[I_i[i] + j];
J[I[i+nrows] + j] = J_i[I_i[i] + j];
D[I[i+nrows] + j] = factor*D_i[I_i[i] + j];
}
}
}
return new SparseMatrix(I, J, D, this->Height(), this->Width());
}
}