phase_t Lattice::enforce_boundary (LatticeSite &site, const BoundaryConditions &bcs) const { BOOST_ASSERT(site.n_dimensions() == n_dimensions()); BOOST_ASSERT(bcs.size() == 0 || bcs.size() == n_dimensions()); phase_t phase_change = 1; for (unsigned int dim = 0; dim < n_dimensions(); ++dim) { while (site[dim] >= dimensions[dim]) { site[dim] -= dimensions[dim]; if (bcs.size() != 0) phase_change *= bcs[dim].phase(); } while (site[dim] < 0) { site[dim] += dimensions[dim]; if (bcs.size() != 0) phase_change *= std::conj(bcs[dim].phase()); } } // this is often unnecessary ... should it be in a separate // function to be called before this one when needed? do_safe_modulus(site.basis_index, basis_indices); BOOST_ASSERT(site_is_valid(site)); return phase_change; }
SymmetricContainer<double> FEM::computeLocalRobinMatrix(BoundaryConditions const & BCs, array<Node, 2>& nodes, double length) { SymmetricContainer<double> r(2); r(0, 0) = length * ( 3. * BCs.RobinCoefficient(nodes[0]) + BCs.RobinCoefficient(nodes[1]) ) / 12.; r(0, 1) = length * ( BCs.RobinCoefficient(nodes[0]) + BCs.RobinCoefficient(nodes[1]) ) / 12.; r(1, 1) = length * ( BCs.RobinCoefficient(nodes[0]) + 3. * BCs.RobinCoefficient(nodes[1]) ) / 12.; return r; }
AmplitudeType BasicOperatorEvaluator::evaluate (const typename Wavefunction<AmplitudeType>::Amplitude &wfa, const BoundaryConditions<AmplitudeType> &bcs) const { typedef AmplitudeType PhaseType; assert(&wfa.get_lattice() == m_operator.lattice.get()); assert(wfa.get_positions().get_N_species() >= min_required_species); const PositionArguments &r = wfa.get_positions(); const Lattice &lattice = wfa.get_lattice(); const bool is_sum_over_sites = (bcs.size() != 0); AmplitudeType meas = 0; const Big<AmplitudeType> old_psi(wfa.psi()); // we only iterate if doing a sum, and even then we only want to iterate // over BraivaisSite's const unsigned int n_iterations = is_sum_over_sites ? lattice.total_sites() / lattice.basis_indices : 1; // FIXME: need a faster way of iterating the lattice for (unsigned int i = 0; i < n_iterations; ++i) { const LatticeSite site_offset(lattice[i]); // we only want to iterate over BravaisSite's assert(site_offset.basis_index == 0); PhaseType phase = 1; Move move; for (unsigned int j = 0; j < m_operator.hopv.size(); ++j) { PhaseType srcphase; const unsigned int species = m_operator.hopv[j].get_species(); LatticeSite src(m_operator.hopv[j].get_source()); lattice.asm_add_site_vector(src, site_offset.bravais_site()); assert(is_sum_over_sites || lattice.site_is_valid(src)); srcphase = lattice.enforce_boundary(src, bcs); if (srcphase == PhaseType(0)) goto current_measurement_is_zero; const int particle_index = r.particle_index_at_position(lattice.index(src), species); if (particle_index < 0) goto current_measurement_is_zero; if (m_operator.hopv[j].get_source() != m_operator.hopv[j].get_destination()) { LatticeSite dest(m_operator.hopv[j].get_destination()); lattice.asm_add_site_vector(dest, site_offset.bravais_site()); assert(is_sum_over_sites || lattice.site_is_valid(dest)); phase *= lattice.enforce_boundary(dest, bcs) / srcphase; if (phase == PhaseType(0)) goto current_measurement_is_zero; const unsigned int dest_index = lattice.index(dest); if (r.is_occupied(dest_index, species)) goto current_measurement_is_zero; move.push_back(SingleParticleMove(Particle(particle_index, species), dest_index)); } } // now perform the move (if necessary) if (move.size() != 0) { BasicOperatorEvaluatorLocal::TemporaryMove<AmplitudeType> temp_move(wfa, move); // fixme: check logic of multiplying by phase (c.f. above), as // well as logic of source and destination meas += vmc_conj(phase * wfa.psi().ratio(old_psi)); } else { meas += 1; } current_measurement_is_zero: ; } return meas; }
vector<double> FEM::computeDiscreteSolution(DiffusionReactionEqn const & PDE, Triangulation& Omega, BoundaryConditions& BCs) { // data structures for final linear system A.xi = b: SymmetricCSlRMatrix A(Omega.generateAdjList()); // build final matrix portrait vector<double> b(Omega.numbOfNodes(), 0.), // load vector xi(Omega.numbOfNodes(), 0.); // discrete solution // data structures for assemby of A and b: SymmetricContainer<double> localMassMatrix(3), // for hat functions on triangles localStiffnessMatrix(3), // we have 3 × 3 element matricies localRobinMatrix(2); // and 2 × 2 element matricies for Robin BCs (just like element matrix in 1D) array<double, 3> localLoadVector; // and their array<double, 2> localRobinVector; // friends, element vectors array<Node, 3> elementNodes, // nodes of the current triangle elementMiddleNodes; // and nodes on the middle of edges array<Node, 2> edgeNodes; // nodes spanning an edge of the current triangle that is part of bndry Node midPoint; // middle point of the edge (to define which BCs to apply) double measure; // area of ith triangle / length of bndry edge of ith thiangle array<size_t, 3> l2g_elem; // local to global mapping of nodes on the element array<size_t, 2> l2g_edge; // and on the edge LocalIndex j, k, leftNodeIndex, rightNodeIndex; // dummy indicies for (size_t i = 0; i < Omega.numbOfTriangles(); ++i) { // (1) quadratures over elements // in order to assemble stiffness matrix and load vector, // it is convenient to iterate over mesh elements (i.e. triangles) elementNodes = Omega.getNodes(i); // get nodes of ith triangle for (j = 0; j < 3; ++j) // and middle nodes of its edges elementMiddleNodes[j] = elementNodes[k = nextIndex(j)].midPoint(elementNodes[nextIndex(k)]); measure = Omega.area(i); // compute area of ith triangle l2g_elem = Omega.l2g(i); // local to global mapping of nodes of ith element // compute // (1.1) local mass matrix, // (1.2) local stiffness matrix, and // (1.3) local load vector localStiffnessMatrix = computeLocalStiffnessMatrix(PDE.diffusionTerm(), elementNodes, elementMiddleNodes, measure); localMassMatrix = computeLocalMassMatrix(PDE.reactionTerm(), elementNodes, measure); localLoadVector = computeLocalLoadVector(PDE.forceTerm(), elementNodes, elementMiddleNodes, measure); // (1.4) assemble contributions for (j = 0; j < 3; ++j) { for (k = j; k < 3; ++k) A(l2g_elem[j], l2g_elem[k]) += localMassMatrix(j, k) + localStiffnessMatrix(j, k); b[l2g_elem[j]] += localLoadVector[j]; } // (2) quadratures over edges // iterate over list of local indicies of boundary nodes for (LocalIndex edgeIndex : Omega.getBoundaryIndicies(i)) { // if edgeIndex = 2, then the edge against second node of ith triangle // is part of the boundary // so we need to assemble BCs here leftNodeIndex = nextIndex(edgeIndex); // local indicies of nodes that rightNodeIndex = nextIndex(leftNodeIndex); // define the edge edgeNodes = { elementNodes[leftNodeIndex], elementNodes[rightNodeIndex] }; // and the nodes themselves l2g_edge[0] = l2g_elem[leftNodeIndex]; // local to global nodes l2g_edge[1] = l2g_elem[rightNodeIndex]; // numeration mapping measure = Omega.length(i, edgeIndex); // define BCs to apply midPoint = edgeNodes[0].midPoint(edgeNodes[1]); BCs.defineBCsAt(midPoint); // compute // (2.1) local Robin matrix // (2.2) local Robin vector localRobinMatrix = computeLocalRobinMatrix(BCs, edgeNodes, measure); localRobinVector = computeLocalRobinVector(BCs, edgeNodes, measure); // (2.3) assemble contributions for (j = 0; j < 2; ++j) { for (k = j; k < 2; ++k) A(l2g_edge[j], l2g_edge[k]) += localRobinMatrix(j, k); b[l2g_edge[j]] += localRobinVector[j]; } } } // now we are ready to compute xi, A.xi = b xi = CG(A, b, xi, 10e-70); return xi; }
array<double, 2> FEM::computeLocalRobinVector(BoundaryConditions const & BCs, array<Node, 2>& nodes, double length) { array<double, 2> r; return (r = { 4. * BCs.NeumannValue(nodes[0]) + 2. * BCs.NeumannValue(nodes[1]) + BCs.DirichletCondition(nodes[0]) * ( 3. * BCs.RobinCoefficient(nodes[0]) + BCs.RobinCoefficient(nodes[1]) ) + BCs.DirichletCondition(nodes[1]) * ( BCs.RobinCoefficient(nodes[0]) + BCs.RobinCoefficient(nodes[1]) ), 2. * BCs.NeumannValue(nodes[0]) + 4. * BCs.NeumannValue(nodes[1]) + BCs.DirichletCondition(nodes[0]) * ( BCs.RobinCoefficient(nodes[0]) + BCs.RobinCoefficient(nodes[1]) ) + BCs.DirichletCondition(nodes[1]) * ( BCs.RobinCoefficient(nodes[0]) + 3. * BCs.RobinCoefficient(nodes[1]) ) }) *= length / 12.; }
// Reference another set of BoundaryConditions void mgrid::BoundaryConditions::reference(const BoundaryConditions& referent) { foreach(BoundaryFlag boundaryFlag, allBoundaryFlags) boundaries(boundaryFlag).reference(referent.boundaries(boundaryFlag)); }