Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from MRChemSoft:master #48

Merged
merged 12 commits into from
Jan 31, 2024
Merged
1 change: 1 addition & 0 deletions api/MWOperators
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@
#include "operators/BSOperator.h"

#include "treebuilders/apply.h"
#include "treebuilders/DerivativeCalculator.h"
13 changes: 13 additions & 0 deletions src/functions/RepresentableFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@

#pragma once

#include <Eigen/Core>
#include <iostream>
#include <vector>

#include "MRCPP/constants.h"
#include "MRCPP/mrcpp_declarations.h"
#include "trees/NodeIndex.h"

namespace mrcpp {

Expand Down Expand Up @@ -74,4 +76,15 @@ template <int D> class RepresentableFunction {
virtual bool isZeroOnInterval(const double *a, const double *b) const { return false; }
};

/*
* Same as RepresentableFunction, but output a matrix of values
* for all points in a node, given its NodeIndex.
*
*/
class RepresentableFunction_M {
public:
RepresentableFunction_M() {}
virtual Eigen::MatrixXd evalf(mrcpp::NodeIndex<3> nIdx) const = 0;
};

} // namespace mrcpp
66 changes: 64 additions & 2 deletions src/treebuilders/DerivativeCalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,34 @@
Printer::setPrecision(oldprec);
}

template <int D> void DerivativeCalculator<D>::calcNode(MWNode<D> &inpNode, MWNode<D> &outNode) {

Check warning on line 89 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L89

Added line #L89 was not covered by tests
//if (this->oper->getMaxBandWidth() > 1) MSG_ABORT("Only implemented for zero bw");
outNode.zeroCoefs();
int nComp = (1 << D);
double tmpCoefs[outNode.getNCoefs()];
OperatorState<D> os(outNode, tmpCoefs);

Check warning on line 94 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L91-L94

Added lines #L91 - L94 were not covered by tests

os.setFNode(inpNode);
os.setFIndex(inpNode.nodeIndex);
for (int ft = 0; ft < nComp; ft++) {
double fNorm = inpNode.getComponentNorm(ft);
if (fNorm < MachineZero) { continue; } // Could this be used outside the loop?
os.setFComponent(ft);
for (int gt = 0; gt < nComp; gt++) {
os.setGComponent(gt);
applyOperator_bw0(os);

Check warning on line 104 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L96-L104

Added lines #L96 - L104 were not covered by tests
}
}
// Multiply appropriate scaling factor. TODO: Could be included elsewhere
const double scaling_factor =
1.0/std::pow(outNode.getMWTree().getMRA().getWorldBox().getScalingFactor(this->applyDir), oper->getOrder());
if(abs(scaling_factor-1.0)>MachineZero){
for (int i = 0; i < outNode.getNCoefs(); i++) outNode.getCoefs()[i] *= scaling_factor;

Check warning on line 111 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L108-L111

Added lines #L108 - L111 were not covered by tests
}
outNode.calcNorms(); //TODO:required? norms are not used for now

Check warning on line 113 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L113

Added line #L113 was not covered by tests
}


template <int D> void DerivativeCalculator<D>::calcNode(MWNode<D> &gNode) {
gNode.zeroCoefs();

Expand All @@ -101,6 +129,7 @@
this->band_t[mrcpp_get_thread_num()].stop();

this->calc_t[mrcpp_get_thread_num()].resume();

for (int n = 0; n < fBand.size(); n++) {
MWNode<D> &fNode = *fBand[n];
NodeIndex<D> &fIdx = idx_band[n];
Expand Down Expand Up @@ -152,6 +181,39 @@
return band;
}

/** Apply a single operator component (term) to a single f-node assuming zero bandwidth */
template <int D> void DerivativeCalculator<D>::applyOperator_bw0(OperatorState<D> &os) {

Check warning on line 185 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L185

Added line #L185 was not covered by tests
//cout<<" applyOperator "<<endl;
MWNode<D> &gNode = *os.gNode;
MWNode<D> &fNode = *os.fNode;
const NodeIndex<D> &fIdx = *os.fIdx;
const NodeIndex<D> &gIdx = gNode.getNodeIndex();
int depth = gNode.getDepth();

Check warning on line 191 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L187-L191

Added lines #L187 - L191 were not covered by tests

double oNorm = 1.0;
double **oData = os.getOperData();

Check warning on line 194 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L193-L194

Added lines #L193 - L194 were not covered by tests

for (int d = 0; d < D; d++) {
const OperatorTree &oTree = this->oper->getComponent(0, d);
const OperatorNode &oNode = oTree.getNode(depth, 0);
int oIdx = os.getOperIndex(d);
if (this->applyDir == d) {
oData[d] = const_cast<double *>(oNode.getCoefs()) + oIdx * os.kp1_2;

Check warning on line 201 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L196-L201

Added lines #L196 - L201 were not covered by tests
} else {
if (oIdx == 0 or oIdx == 3) {

Check warning on line 203 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L203

Added line #L203 was not covered by tests
// This will activate the identity operator in direction i
oData[d] = nullptr;

Check warning on line 205 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L205

Added line #L205 was not covered by tests
} else {
// This means that we are in a zero part of the identity operator
return;
}
}
}
this->operStat.incrementFNodeCounters(fNode, os.ft, os.gt);
tensorApplyOperComp(os);

Check warning on line 213 in src/treebuilders/DerivativeCalculator.cpp

View check run for this annotation

Codecov / codecov/patch

src/treebuilders/DerivativeCalculator.cpp#L212-L213

Added lines #L212 - L213 were not covered by tests
}


/** Apply a single operator component (term) to a single f-node. Whether the
operator actualy is applied is determined by a screening threshold. */
template <int D> void DerivativeCalculator<D>::applyOperator(OperatorState<D> &os) {
Expand Down Expand Up @@ -197,8 +259,8 @@
tensorApplyOperComp(os);
}

/** Perorm the required linear algebra operations in order to apply an
operator component to a f-node in a n-dimensional tesor space. */
/** Perform the required linear algebra operations in order to apply an
operator component to a f-node in a n-dimensional tensor space. */
template <int D> void DerivativeCalculator<D>::tensorApplyOperComp(OperatorState<D> &os) {
double **aux = os.getAuxData();
double **oData = os.getOperData();
Expand Down
2 changes: 2 additions & 0 deletions src/treebuilders/DerivativeCalculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ template <int D> class DerivativeCalculator final : public TreeCalculator<D> {
~DerivativeCalculator() override;

MWNodeVector<D> *getInitialWorkVector(MWTree<D> &tree) const override;
void calcNode(MWNode<D> &fNode, MWNode<D> &gNode);

private:
int applyDir;
Expand All @@ -61,6 +62,7 @@ template <int D> class DerivativeCalculator final : public TreeCalculator<D> {
}

void applyOperator(OperatorState<D> &os);
void applyOperator_bw0(OperatorState<D> &os);
void tensorApplyOperComp(OperatorState<D> &os);
};

Expand Down
2 changes: 1 addition & 1 deletion src/treebuilders/apply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ template <int D> void apply_far_field(double prec, FunctionTree<D> &out, Convolu
template <int D> void apply_near_field(double prec, FunctionTree<D> &out, ConvolutionOperator<D> &oper, FunctionTree<D> &inp, int maxIter, bool absPrec) {
apply_on_unit_cell<D>(true, prec, out, oper, inp, maxIter, absPrec);
}

/** @brief Application of MW derivative operator
*
* @param[out] out: Output function to be built
Expand All @@ -274,7 +275,6 @@ template <int D> void apply_near_field(double prec, FunctionTree<D> &out, Convol
*/
template <int D> void apply(FunctionTree<D> &out, DerivativeOperator<D> &oper, FunctionTree<D> &inp, int dir) {
if (out.getMRA() != inp.getMRA()) MSG_ABORT("Incompatible MRA");

TreeBuilder<D> builder;
int maxScale = out.getMRA().getMaxScale();

Expand Down
50 changes: 49 additions & 1 deletion src/trees/FunctionNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@
int qOrder = this->getKp1();
getQuadratureCache(qc);
const VectorXd &weights = qc.getWeights(qOrder);

double sqWeights[qOrder];
for (int i = 0; i < qOrder; i++) sqWeights[i] = std::sqrt(weights[i]);

Expand Down Expand Up @@ -158,6 +157,52 @@
return two_n * sum;
}

/** Function integration, Interpolating basis.
*
* Integrates the function represented on the node on the full support of the
* node. A bit more involved than in the Legendre basis, as is requires some
* coupling of quadrature weights. */
template <int D> double FunctionNode<D>::integrateValues() const {
int qOrder = this->getKp1();
getQuadratureCache(qc);
const VectorXd &weights = qc.getWeights(qOrder);
VectorXd coefs;
this->getCoefs(coefs);
int ncoefs = coefs.size();
int ncoefChild = ncoefs/(1<<D);
double cc[ncoefChild];

Check warning on line 173 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L165-L173

Added lines #L165 - L173 were not covered by tests
// factorize out the children
for (int i = 0; i < ncoefChild; i++)cc[i]=coefs[i];
for (int j = 1; j < (1<<D); j++) for (int i = 0; i < ncoefChild; i++)cc[i]+=coefs[j*ncoefChild+i];

Check warning on line 176 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L175-L176

Added lines #L175 - L176 were not covered by tests

int nc = 0;
double sum = 0.0;
if (D > 3) MSG_ABORT("Not Implemented")
else if (D == 3) {
for (int i = 0; i < qOrder; i++) {

Check warning on line 182 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L182

Added line #L182 was not covered by tests
double sumj = 0.0;
for (int j = 0; j < qOrder; j++) {

Check warning on line 184 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L184

Added line #L184 was not covered by tests
double sumk = 0.0;
for (int k = 0; k < qOrder; k++) sumk += cc[nc++] * weights[k];
sumj += sumk * weights[j];

Check warning on line 187 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L186-L187

Added lines #L186 - L187 were not covered by tests
}
sum += sumj * weights[i];

Check warning on line 189 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L189

Added line #L189 was not covered by tests
}
} else if (D==2) {
for (int j = 0; j < qOrder; j++) {

Check warning on line 192 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L192

Added line #L192 was not covered by tests
double sumk = 0.0;
for (int k = 0; k < qOrder; k++) sumk += cc[nc++] * weights[k];
sum += sumk * weights[j];

Check warning on line 195 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L194-L195

Added lines #L194 - L195 were not covered by tests
}
} else if (D==1) for (int k = 0; k < qOrder; k++) sum += cc[nc++] * weights[k];

Check warning on line 197 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L197

Added line #L197 was not covered by tests

int n = D * (this->getScale() + 1) ; // NB: one extra scale
int two_n = (1<<abs(n)); // 2**n;
if(n>0)sum/=two_n;
else sum*=two_n;
return sum;

Check warning on line 203 in src/trees/FunctionNode.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionNode.cpp#L199-L203

Added lines #L199 - L203 were not covered by tests
}

template <int D> void FunctionNode<D>::setValues(const VectorXd &vec) {
this->zeroCoefs();
this->setCoefBlock(0, vec.size(), vec.data());
Expand Down Expand Up @@ -319,6 +364,9 @@
auto &ftree = this->getFuncTree();
if (this->isGenNode()) {
ftree.getGenNodeAllocator().dealloc(sIdx);
// for GenNodes we clean unused chunks carefully, as they can become
// very large and occupy space long after used.
ftree.getGenNodeAllocator().deleteUnusedChunks();
} else {
ftree.decrementNodeCount(this->getScale());
ftree.getNodeAllocator().dealloc(sIdx);
Expand Down
1 change: 1 addition & 0 deletions src/trees/FunctionNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ template <int D> class FunctionNode final : public MWNode<D> {

double integrateLegendre() const;
double integrateInterpolating() const;
double integrateValues() const;
};

template <int D> double dot_scaling(const FunctionNode<D> &bra, const FunctionNode<D> &ket);
Expand Down
38 changes: 37 additions & 1 deletion src/trees/FunctionTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
FunctionTree<D>::FunctionTree(const MultiResolutionAnalysis<D> &mra, SharedMemory *sh_mem, const std::string &name)
: MWTree<D>(mra, name)
, RepresentableFunction<D>(mra.getWorldBox().getLowerBounds().data(), mra.getWorldBox().getUpperBounds().data()) {
int nodesPerChunk = 64;
int nodesPerChunk = 2048; // Large chunks are required for not leading to memory fragmentation (32 MB on "Betzy" 2023)
int coefsGenNodes = this->getKp1_d();
int coefsRegNodes = this->getTDim() * this->getKp1_d();
this->nodeAllocator_p = std::make_unique<NodeAllocator<D>>(this, sh_mem, coefsRegNodes, nodesPerChunk);
Expand Down Expand Up @@ -186,6 +186,42 @@
return jacobian * result;
}


/** @returns Integral of a representable function over the grid given by the tree */
template <> double FunctionTree<3>::integrateEndNodes(RepresentableFunction_M &f) {

Check warning on line 191 in src/trees/FunctionTree.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionTree.cpp#L191

Added line #L191 was not covered by tests
//traverse tree, and treat end nodes only
std::vector<FunctionNode<3> *> stack; // node from this
for (int i = 0; i < this->getRootBox().size(); i++) stack.push_back(&(this->getRootFuncNode(i)));
int basis = getMRA().getScalingBasis().getScalingType();
double result = 0.0;
while (stack.size() > 0) {
FunctionNode<3> *Node = stack.back();
stack.pop_back();
if (Node->getNChildren() > 0) {
for (int i = 0; i < Node->getNChildren(); i++) stack.push_back(&(Node->getFuncChild(i)));

Check warning on line 201 in src/trees/FunctionTree.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionTree.cpp#L193-L201

Added lines #L193 - L201 were not covered by tests
} else {
//end nodes
Eigen::MatrixXd fmat = f.evalf(Node->nodeIndex);
double *coefs = Node->getCoefs(); // save position of coeff, but do not use them!

Check warning on line 205 in src/trees/FunctionTree.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionTree.cpp#L204-L205

Added lines #L204 - L205 were not covered by tests
// The data in fmat is not organized so that two consecutive points are stored after each other in memory, so needs to copy before mwtransform, cannot use memory adress directly.
int nc=fmat.cols();
double cc[nc];
for (int i = 0; i < nc; i++)cc[i]=fmat(0,i);
Node->attachCoefs(cc);
result += Node->integrateValues();
Node->attachCoefs(coefs); // put back original coeff

Check warning on line 212 in src/trees/FunctionTree.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionTree.cpp#L207-L212

Added lines #L207 - L212 were not covered by tests
}
}

// Handle potential scaling
auto scaling_factor = this->getMRA().getWorldBox().getScalingFactors();
auto jacobian = 1.0;
for (const auto &sf_i : scaling_factor) jacobian *= std::sqrt(sf_i);

Check warning on line 219 in src/trees/FunctionTree.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionTree.cpp#L217-L219

Added lines #L217 - L219 were not covered by tests
// Square root of scaling factor in each diection. The seemingly missing
// multiplication by the square root of sf_i is included in the basis
return jacobian * result;

Check warning on line 222 in src/trees/FunctionTree.cpp

View check run for this annotation

Codecov / codecov/patch

src/trees/FunctionTree.cpp#L222

Added line #L222 was not covered by tests
}

/** @returns Function value in a point, out of bounds returns zero
*
* @param[in] r: Cartesian coordinate
Expand Down
1 change: 1 addition & 0 deletions src/trees/FunctionTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ template <int D> class FunctionTree final : public MWTree<D>, public Representab
~FunctionTree() override;

double integrate() const;
double integrateEndNodes(RepresentableFunction_M &f);
double evalf_precise(const Coord<D> &r);
double evalf(const Coord<D> &r) const override;

Expand Down
16 changes: 8 additions & 8 deletions src/trees/MWNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ MWNode<D>::MWNode(MWTree<D> *tree, int rIdx)
/** @brief MWNode constructor.
*
* @param[in] parent: parent node
* @param[in] cIdx: child index of the current node
* @param[in] cIdx: child index of the current node
*
* @details Constructor for leaf nodes. It requires the corresponding
* parent and an integer to identify the correct child.
Expand Down Expand Up @@ -131,7 +131,7 @@ MWNode<D>::MWNode(MWNode<D> *parent, int cIdx)
* the tree.
*/
template <int D>
MWNode<D>::MWNode(const MWNode<D> &node, bool allocCoef)
MWNode<D>::MWNode(const MWNode<D> &node, bool allocCoef, bool SetCoef)
: tree(node.tree)
, parent(nullptr)
, nodeIndex(node.nodeIndex)
Expand All @@ -141,7 +141,7 @@ MWNode<D>::MWNode(const MWNode<D> &node, bool allocCoef)
setIsLooseNode();
if (allocCoef) {
allocCoefs(this->getTDim(), this->getKp1_d());
if (node.hasCoefs()) {
if (node.hasCoefs() and SetCoef) {
setCoefBlock(0, node.getNCoefs(), node.getCoefs());
if (this->getNCoefs() > node.getNCoefs()) {
for (int i = node.getNCoefs(); i < this->getNCoefs(); i++) this->coefs[i] = 0.0;
Expand Down Expand Up @@ -236,7 +236,7 @@ template <int D> void MWNode<D>::getCoefs(Eigen::VectorXd &c) const {
c = VectorXd::Map(this->coefs, this->n_coefs);
}

/** @brief sets all MW coefficients and the norms to zero
/** @brief sets all MW coefficients and the norms to zero
*
*/
template <int D> void MWNode<D>::zeroCoefs() {
Expand Down Expand Up @@ -388,7 +388,7 @@ template <int D> void MWNode<D>::giveParentCoefs(bool overwrite) {
}

/** @brief Copy scaling coefficients from children to parent
*
*
* @details Takes the scaling coefficients of the children and stores
* them consecutively in the corresponding block of the parent,
* following the usual bitwise notation.
Expand All @@ -404,7 +404,7 @@ template <int D> void MWNode<D>::copyCoefsFromChildren() {
}

/** @brief Generates scaling cofficients of children
*
*
* @details If the node is a leafNode, it takes the scaling&wavelet
* coefficients of the parent and it generates the scaling
* coefficients for the children
Expand Down Expand Up @@ -835,7 +835,7 @@ template <int D> void MWNode<D>::getPrimitiveQuadPts(MatrixXd &pts) const {
* the set of quadrature points becomes \f$ x^\alpha_i = 2^{-n-1} (x_i + 2 l^\alpha + t^\alpha) \f$, where \f$ t^\alpha =
* 0,1 \f$. By taking all possible \f$(k+1)^d\combinations \f$, they will
* then define a d-dimensional grid of quadrature points for the child
* nodes.
* nodes.
*
*/
template <int D> void MWNode<D>::getPrimitiveChildPts(MatrixXd &pts) const {
Expand Down Expand Up @@ -879,7 +879,7 @@ template <int D> void MWNode<D>::getExpandedQuadPts(Eigen::MatrixXd &pts) const

/** @brief Returns the quadrature points in a given node
*
* @param[in,out] pts: expanded quadrature points in a \f$ d \times
* @param[in,out] pts: expanded quadrature points in a \f$ d \times
* 2^d(k+1)^d \f$ matrix form.
*
* @details The primitive quadrature points of the children are used to obtain a
Expand Down
Loading
Loading