00001
00002
00003
00004
00005
00006 #include "MOR_GreedyAtomicBasisSample.hpp"
00007
00008 #include "MOR_CollocationMetricCriterion.hpp"
00009 #include "MOR_MinMaxTools.hpp"
00010
00011 #include "Epetra_SerialDenseMatrix.h"
00012 #include "Epetra_SerialSymDenseMatrix.h"
00013 #include "Epetra_Comm.h"
00014
00015 #include "Thyra_EpetraThyraWrappers.hpp"
00016
00017 #include "Teuchos_RCP.hpp"
00018 #include "Teuchos_Array.hpp"
00019 #include "Teuchos_Comm.hpp"
00020
00021 #include "Teuchos_Assert.hpp"
00022
00023 #include <utility>
00024 #include <algorithm>
00025
00026 namespace MOR {
00027
00028 namespace Detail {
00029
00030 Teuchos::Array<Epetra_SerialDenseMatrix>
00031 createAtomicSections(MOR::AtomicBasisSource &basisSource)
00032 {
00033 const Epetra_Map atomMap = basisSource.atomMap();
00034 const int ownedAtomCount = atomMap.NumMyElements();
00035 const int vectorCount = basisSource.vectorCount();
00036
00037
00038 Teuchos::Array<Epetra_SerialDenseMatrix> result(ownedAtomCount);
00039 for (int iAtom = 0; iAtom < ownedAtomCount; ++iAtom) {
00040 TEUCHOS_ASSERT(atomMap.MyLID(iAtom));
00041 result[iAtom].Shape(basisSource.entryCount(iAtom), vectorCount);
00042 }
00043
00044
00045 for (int vectorRank = 0; vectorRank < vectorCount; ++vectorRank) {
00046 basisSource.currentVectorRankIs(vectorRank);
00047 for (int iAtom = 0; iAtom < ownedAtomCount; ++iAtom) {
00048 Teuchos::ArrayView<double> target(result[iAtom][vectorRank], basisSource.entryCount(iAtom));
00049 basisSource.atomData(iAtom, target);
00050 }
00051 }
00052
00053 return result;
00054 }
00055
00056 Teuchos::Array<Epetra_SerialSymDenseMatrix>
00057 createAtomicContributions(const Teuchos::ArrayView<const Epetra_SerialDenseMatrix> &atomicSections) {
00058 const int sectionCount = atomicSections.size();
00059 Teuchos::Array<Epetra_SerialSymDenseMatrix> result(sectionCount);
00060
00061 for (int i = 0; i < sectionCount; ++i) {
00062 const Epetra_SerialDenseMatrix §ion = atomicSections[i];
00063 Epetra_SerialSymDenseMatrix &contribution = result[i];
00064
00065 const int contributionSize = section.ColDim();
00066 if (contributionSize > 0) {
00067 contribution.Shape(contributionSize);
00068 contribution.Multiply('T', 'N', 1.0, section, section, 0.0);
00069 }
00070 }
00071
00072 return result;
00073 }
00074
00075 Teuchos::Array<Epetra_SerialSymDenseMatrix>
00076 createAtomicContributions(MOR::AtomicBasisSource &basisSource)
00077 {
00078 return createAtomicContributions(createAtomicSections(basisSource));
00079 }
00080
00081 Teuchos::Array<double>
00082 computePartialFitnesses(
00083 const Epetra_SerialSymDenseMatrix &reference,
00084 const Teuchos::ArrayView<const Epetra_SerialSymDenseMatrix> &atomicContributions,
00085 const CollocationMetricCriterion &criterion,
00086 int referenceContributionCount)
00087 {
00088 const int localAtomCount = atomicContributions.size();
00089 Teuchos::Array<double> result(localAtomCount);
00090
00091 if (!result.empty()) {
00092 Epetra_SerialSymDenseMatrix candidate;
00093 const int candidateContributionCount = referenceContributionCount + 1;
00094
00095 for (int iAtom = 0; iAtom < localAtomCount; ++iAtom) {
00096 {
00097 candidate = reference;
00098 candidate += atomicContributions[iAtom];
00099 }
00100 result[iAtom] = criterion.partialFitness(candidate, candidateContributionCount);
00101 }
00102 }
00103
00104 return result;
00105 }
00106
00107 Epetra_SerialSymDenseMatrix negative_eye(int size) {
00108 Epetra_SerialSymDenseMatrix result;
00109 result.Shape(size);
00110 for (int i = 0; i < size; ++i) {
00111 result[i][i] = -1.0;
00112 }
00113 return result;
00114 }
00115
00116 template <typename Ordinal>
00117 void broadcast(const Teuchos::Comm<Ordinal> &comm, int rootRank, Epetra_SerialDenseMatrix &buffer) {
00118 const int count = buffer.LDA() * buffer.N();
00119 Teuchos::broadcast<Ordinal, double>(comm, rootRank, count, buffer.A());
00120 }
00121
00122 int
00123 bestCandidateId(
00124 const Epetra_Map &candidateMap,
00125 const Teuchos::ArrayView<const Epetra_SerialSymDenseMatrix> &candidates,
00126 Epetra_SerialSymDenseMatrix &reference,
00127 const CollocationMetricCriterion &criterion,
00128 int referenceContributionCount)
00129 {
00130 const Teuchos::Array<double> fitnesses =
00131 computePartialFitnesses(reference, candidates, criterion, referenceContributionCount);
00132
00133 const Teuchos::RCP<const Teuchos::Comm<Thyra::Ordinal> > comm =
00134 Thyra::create_Comm(Teuchos::rcpFromRef(candidateMap.Comm()));
00135
00136 const Teuchos::ArrayView<int> ids(candidateMap.MyGlobalElements(), candidateMap.NumMyElements());
00137 return MOR::globalIdOfGlobalMinimum(*comm, ids, fitnesses);
00138 }
00139
00140 void
00141 updateReferenceAndCandidates(
00142 const Epetra_Map &candidateMap,
00143 Teuchos::ArrayView<Epetra_SerialSymDenseMatrix> candidates,
00144 int selectedId,
00145 Epetra_SerialSymDenseMatrix &reference)
00146 {
00147 int selectedIdCpu;
00148 int selectedLocalId;
00149 candidateMap.RemoteIDList(1, &selectedId, &selectedIdCpu, &selectedLocalId);
00150 const bool selectedCandidateIsLocal = (selectedIdCpu == candidateMap.Comm().MyPID());
00151
00152 if (selectedCandidateIsLocal) {
00153 Epetra_SerialSymDenseMatrix &selectedCandidate = candidates[selectedLocalId];
00154 reference += selectedCandidate;
00155 selectedCandidate.Scale(0.0);
00156 }
00157 const Teuchos::RCP<const Teuchos::Comm<Thyra::Ordinal> > comm =
00158 Thyra::create_Comm(Teuchos::rcpFromRef(candidateMap.Comm()));
00159 broadcast(*comm, selectedIdCpu, reference);
00160 }
00161
00162 }
00163
00164 GreedyAtomicBasisSample::GreedyAtomicBasisSample(
00165 AtomicBasisSource &basisSource,
00166 const Teuchos::RCP<const CollocationMetricCriterion> &criterion) :
00167 criterion_(criterion),
00168 atomMap_(basisSource.atomMap()),
00169 contributions_(Detail::createAtomicContributions(basisSource)),
00170 discrepancy_(Detail::negative_eye((contributions_.size() > 0) ? contributions_.front().RowDim() : 0)),
00171 sample_()
00172 {
00173
00174 }
00175
00176 void
00177 GreedyAtomicBasisSample::sampleSizeInc(int incr) {
00178 for (int iter = 0; iter < incr; ++iter) {
00179 const int selectedId = Detail::bestCandidateId(atomMap_, contributions_, discrepancy_, *criterion_, iter);
00180 Detail::updateReferenceAndCandidates(atomMap_, contributions_, selectedId, discrepancy_);;
00181 sample_.push_back(selectedId);
00182 }
00183 }
00184
00185 }