00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "EpetraExt_ProductOperator.h"
00030 #include "Epetra_Vector.h"
00031 #include "Epetra_Map.h"
00032
00033 namespace EpetraExt {
00034
00035
00036
00037 ProductOperator::ProductOperator()
00038 {}
00039
00040 ProductOperator::ProductOperator(
00041 const int num_Op
00042 ,const Teuchos::RefCountPtr<const Epetra_Operator> Op[]
00043 ,const Teuchos::ETransp Op_trans[]
00044 ,const EApplyMode Op_inverse[]
00045 )
00046 {
00047 initialize(num_Op,Op,Op_trans,Op_inverse);
00048 }
00049
00050 void ProductOperator::initialize(
00051 const int num_Op
00052 ,const Teuchos::RefCountPtr<const Epetra_Operator> Op[]
00053 ,const Teuchos::ETransp Op_trans[]
00054 ,const EApplyMode Op_inverse[]
00055 )
00056 {
00057 #ifdef _DEBUG
00058 TEST_FOR_EXCEPTION(
00059 num_Op < 1, std::invalid_argument
00060 ,"ProductOperator::initialize(...): Error!"
00061 );
00062
00063 #endif // _DEBUG
00064 Op_.resize(num_Op);
00065 Op_trans_.resize(num_Op);
00066 Op_inverse_.resize(num_Op);
00067 std::copy( Op, Op + num_Op, Op_.begin() );
00068 std::copy( Op_trans, Op_trans + num_Op, Op_trans_.begin() );
00069 std::copy( Op_inverse, Op_inverse + num_Op, Op_inverse_.begin() );
00070 UseTranspose_ = false;
00071
00072 range_vecs_.resize(0);
00073 domain_vecs_.resize(0);
00074 }
00075
00076 void ProductOperator::uninitialize(
00077 int *num_Op
00078 ,Teuchos::RefCountPtr<const Epetra_Operator> Op[]
00079 ,Teuchos::ETransp Op_trans[]
00080 ,EApplyMode Op_inverse[]
00081 )
00082 {
00083 #ifdef _DEBUG
00084 TEST_FOR_EXCEPTION(
00085 (Op!=NULL || Op_trans!=NULL || Op_inverse!=NULL) && num_Op==NULL
00086 ,std::invalid_argument
00087 ,"ProductOperator::uninitialize(...): Error!"
00088 );
00089 #endif // _DEBUG
00090 if(num_Op) {
00091 *num_Op = Op_.size();
00092 if(Op) std::copy( Op_.begin(), Op_.end(), Op );
00093 if(Op_trans) std::copy( Op_trans_.begin(), Op_trans_.end(), Op_trans );
00094 if(Op_inverse) std::copy( Op_inverse_.begin(), Op_inverse_.end(), Op_inverse );
00095 }
00096 UseTranspose_ = false;
00097 Op_.resize(0);
00098 Op_trans_.resize(0);
00099 Op_inverse_.resize(0);
00100 range_vecs_.resize(0);
00101 domain_vecs_.resize(0);
00102 }
00103
00104 void ProductOperator::applyConstituent(
00105 const int k
00106 ,Teuchos::ETransp Op_trans
00107 ,EApplyMode Op_inverse
00108 ,const Epetra_MultiVector &X_k
00109 ,Epetra_MultiVector *Y_k
00110 ) const
00111 {
00112 Epetra_Operator &Op_k = const_cast<Epetra_Operator&>(*Op_[k]);
00113 bool oldUseTranspose = Op_k.UseTranspose();
00114 Op_k.SetUseTranspose((Op_trans==Teuchos::NO_TRANS)!=(Op_trans_[k]==Teuchos::NO_TRANS));
00115 const bool applyInverse_k = (Op_inverse==APPLY_MODE_APPLY)!=(Op_inverse_[k]==APPLY_MODE_APPLY);
00116 const int err = !applyInverse_k ? Op_[k]->Apply(X_k,*Y_k) : Op_[k]->ApplyInverse(X_k,*Y_k);
00117 Op_k.SetUseTranspose(oldUseTranspose);
00118 TEST_FOR_EXCEPTION(
00119 err!=0, std::runtime_error
00120 ,"ProductOperator::applyConstituent(...): Error, Op["<<k<<"]."
00121 <<(!applyInverse_k?"Apply":"ApplyInverse")<<"(...) returned "
00122 "err = "<<err<<" with Op["<<k<<"].UseTranspose() = "<<Op_[k]->UseTranspose()<<"!"
00123 );
00124 }
00125
00126
00127
00128 int ProductOperator::SetUseTranspose(bool UseTranspose)
00129 {
00130 assertInitialized();
00131 UseTranspose_ = UseTranspose;
00132 return 0;
00133 }
00134
00135 int ProductOperator::Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00136 {
00137 assertInitialized();
00138 const int num_Op = this->num_Op();
00139
00140 initializeTempVecs(false);
00141
00142 if( !UseTranspose_ ) {
00143
00144
00145
00146 for( int k = num_Op-1; k >= 0; --k ) {
00147 const Epetra_MultiVector &X_k = ( k==num_Op-1 ? X : *range_vecs_[k] );
00148 Epetra_MultiVector &Y_k = ( k==0 ? Y : *range_vecs_[k-1] );
00149 applyConstituent(k,Teuchos::NO_TRANS,APPLY_MODE_APPLY,X_k,&Y_k);
00150 }
00151 }
00152 else if( UseTranspose_ ) {
00153
00154
00155
00156 for( int k = 0; k <= num_Op-1; ++k ) {
00157 const Epetra_MultiVector &X_k = ( k==0 ? X : *domain_vecs_[k-1] );
00158 Epetra_MultiVector &Y_k = ( k==num_Op-1 ? Y : *domain_vecs_[k] );
00159 applyConstituent(k,Teuchos::TRANS,APPLY_MODE_APPLY,X_k,&Y_k);
00160 }
00161 }
00162 return 0;
00163 }
00164
00165 int ProductOperator::ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00166 {
00167 assertInitialized();
00168 const int num_Op = this->num_Op();
00169
00170 initializeTempVecs(true);
00171
00172 if( !UseTranspose_ ) {
00173
00174
00175
00176 for( int k = 0; k <= num_Op-1; ++k ) {
00177 const Epetra_MultiVector &X_k = ( k==0 ? X : *domain_vecs_[k-1] );
00178 Epetra_MultiVector &Y_k = ( k==num_Op-1 ? Y : *domain_vecs_[k] );
00179 applyConstituent(k,Teuchos::NO_TRANS,APPLY_MODE_APPLY_INVERSE,X_k,&Y_k);
00180 }
00181 }
00182 else if( UseTranspose_ ) {
00183
00184
00185
00186 for( int k = num_Op-1; k >= 0; --k ) {
00187 const Epetra_MultiVector &X_k = ( k==num_Op-1 ? X : *range_vecs_[k] );
00188 Epetra_MultiVector &Y_k = ( k==0 ? Y : *range_vecs_[k-1] );
00189 applyConstituent(k,Teuchos::TRANS,APPLY_MODE_APPLY_INVERSE,X_k,&Y_k);
00190 }
00191 }
00192 return 0;
00193 }
00194
00195 double ProductOperator::NormInf() const
00196 {
00197 assertInitialized();
00198 return -1.0;
00199 }
00200
00201 const char* ProductOperator::Label() const
00202 {
00203 assertInitialized();
00204 return NULL;
00205 }
00206
00207 bool ProductOperator::UseTranspose() const
00208 {
00209 assertInitialized();
00210 return UseTranspose_;
00211 }
00212
00213 bool ProductOperator::HasNormInf() const
00214 {
00215 assertInitialized();
00216 return false;
00217 }
00218
00219 const Epetra_Comm&
00220 ProductOperator::Comm() const
00221 {
00222 assertInitialized();
00223 return Op_.front()->OperatorRangeMap().Comm();
00224 }
00225
00226 const Epetra_Map&
00227 ProductOperator::OperatorDomainMap() const
00228 {
00229 assertInitialized();
00230 return ( Op_trans_.back()==Teuchos::NO_TRANS
00231 ? Op_.back()->OperatorDomainMap()
00232 : Op_.back()->OperatorRangeMap()
00233 );
00234 }
00235
00236 const Epetra_Map&
00237 ProductOperator::OperatorRangeMap() const
00238 {
00239 assertInitialized();
00240 return ( Op_trans_.front()==Teuchos::NO_TRANS
00241 ? Op_.front()->OperatorRangeMap()
00242 : Op_.front()->OperatorDomainMap()
00243 );
00244 }
00245
00246
00247
00248 void ProductOperator::initializeTempVecs(bool applyInverse) const
00249 {
00250 const int num_Op = this->num_Op();
00251 if( num_Op > 0 ) {
00252 if( ( !UseTranspose_ && !applyInverse ) || ( UseTranspose_ && applyInverse )
00253 && range_vecs_.size()==0
00254 )
00255 {
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 range_vecs_.resize(num_Op-1);
00268 for( int k = num_Op-1; k >= 1; --k ) {
00269 range_vecs_[k-1] = Teuchos::rcp(
00270 new Epetra_Vector(
00271 (Op_trans_[k]==Teuchos::NO_TRANS) == (Op_inverse_[k]==APPLY_MODE_APPLY)
00272 ? Op_[k]->OperatorRangeMap()
00273 : Op_[k]->OperatorDomainMap()
00274 )
00275 );
00276 }
00277 }
00278 else if( ( UseTranspose_ && !applyInverse ) || ( !UseTranspose_ && applyInverse )
00279 && domain_vecs_.size()==0
00280 )
00281 {
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 domain_vecs_.resize(num_Op-1);
00294 for( int k = 0; k <= num_Op-2; ++k ) {
00295 domain_vecs_[k] = Teuchos::rcp(
00296 new Epetra_Vector(
00297 (Op_trans_[k]==Teuchos::NO_TRANS) == (Op_inverse_[k]==APPLY_MODE_APPLY)
00298 ? Op_[k]->OperatorDomainMap()
00299 : Op_[k]->OperatorRangeMap()
00300 )
00301 );
00302 }
00303 }
00304 }
00305 }
00306
00307 }