| [de061d] | 1 | /*
 | 
|---|
 | 2 |  *    vmg - a versatile multigrid solver
 | 
|---|
 | 3 |  *    Copyright (C) 2012 Institute for Numerical Simulation, University of Bonn
 | 
|---|
 | 4 |  *
 | 
|---|
 | 5 |  *  vmg is free software: you can redistribute it and/or modify
 | 
|---|
 | 6 |  *  it under the terms of the GNU General Public License as published by
 | 
|---|
 | 7 |  *  the Free Software Foundation, either version 3 of the License, or
 | 
|---|
 | 8 |  *  (at your option) any later version.
 | 
|---|
 | 9 |  *
 | 
|---|
 | 10 |  *  vmg is distributed in the hope that it will be useful,
 | 
|---|
 | 11 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
 | 12 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
 | 13 |  *  GNU General Public License for more details.
 | 
|---|
 | 14 |  *
 | 
|---|
 | 15 |  *  You should have received a copy of the GNU General Public License
 | 
|---|
 | 16 |  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
 | 17 |  */
 | 
|---|
 | 18 | 
 | 
|---|
 | 19 | #ifdef HAVE_CONFIG_H
 | 
|---|
 | 20 | #include <libvmg_config.h>
 | 
|---|
 | 21 | #endif
 | 
|---|
 | 22 | 
 | 
|---|
 | 23 | #include <vector>
 | 
|---|
 | 24 | 
 | 
|---|
 | 25 | #include "base/helper.hpp"
 | 
|---|
 | 26 | #include "base/index.hpp"
 | 
|---|
 | 27 | #include "base/vector.hpp"
 | 
|---|
 | 28 | #include "grid/grid.hpp"
 | 
|---|
 | 29 | #include "units/particle/interpolation.hpp"
 | 
|---|
 | 30 | #include "units/particle/particle.hpp"
 | 
|---|
 | 31 | 
 | 
|---|
 | 32 | #include "mg.hpp"
 | 
|---|
 | 33 | #include "comm/comm.hpp"
 | 
|---|
 | 34 | 
 | 
|---|
 | 35 | using namespace VMG;
 | 
|---|
 | 36 | 
 | 
|---|
 | 37 | Particle::Interpolation::Interpolation(const int& degree) :
 | 
|---|
 | 38 |   deg(degree),
 | 
|---|
 | 39 |   deg_1(degree+1),
 | 
|---|
 | 40 |   buffer(degree+1),
 | 
|---|
 | 41 |   buffer_diff(degree)
 | 
|---|
 | 42 | {
 | 
|---|
 | 43 |   coeff = new vmg_float[Helper::intpow(deg_1, 3)];
 | 
|---|
 | 44 |   coeff_buffer = new vmg_float[deg_1];
 | 
|---|
 | 45 |   for (int i=0; i<degree; ++i)
 | 
|---|
 | 46 |     buffer_diff[i].resize(i+1);
 | 
|---|
 | 47 | }
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 | Particle::Interpolation::~Interpolation()
 | 
|---|
 | 50 | {
 | 
|---|
 | 51 |   delete [] coeff;
 | 
|---|
 | 52 |   delete [] coeff_buffer;
 | 
|---|
 | 53 | }
 | 
|---|
 | 54 | 
 | 
|---|
 | 55 | void Particle::Interpolation::ComputeCoefficients(const Grid& grid, const Index& index)
 | 
|---|
 | 56 | {
 | 
|---|
 | 57 |   Index i;
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 |   const Index begin = index - deg/2;
 | 
|---|
 | 60 | 
 | 
|---|
 | 61 |   h = grid.Extent().MeshWidth();
 | 
|---|
 | 62 | 
 | 
|---|
 | 63 |   for (i[0]=0; i[0]<deg_1; ++i[0])
 | 
|---|
 | 64 |     for (i[1]=0; i[1]<deg_1; ++i[1])
 | 
|---|
 | 65 |       for (i[2]=0; i[2]<deg_1; ++i[2])
 | 
|---|
 | 66 |         _access_coeff(i) = grid.GetVal(i+begin);
 | 
|---|
 | 67 | 
 | 
|---|
 | 68 |   pos_begin = grid.Extent().Begin()
 | 
|---|
 | 69 |     + (begin - grid.Local().Begin() + grid.Global().LocalBegin() - grid.Global().GlobalBegin()) * grid.Extent().MeshWidth();
 | 
|---|
 | 70 | 
 | 
|---|
 | 71 |   // compute coefficients x-direction
 | 
|---|
 | 72 |   for (i=0; i[1]<deg_1; ++i[1])
 | 
|---|
 | 73 |     for (i[2]=0; i[2]<deg_1; ++i[2])
 | 
|---|
 | 74 |       _compute_coefficients_1d(i, 0);
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 |   // compute coefficients y-direction
 | 
|---|
 | 77 |   for (i=0; i[0]<deg_1; ++i[0])
 | 
|---|
 | 78 |     for (i[2]=0; i[2]<deg_1; ++i[2])
 | 
|---|
 | 79 |       _compute_coefficients_1d(i, 1);
 | 
|---|
 | 80 | 
 | 
|---|
 | 81 |   // compute coefficients z-direction
 | 
|---|
 | 82 |   for (i=0; i[0]<deg_1; ++i[0])
 | 
|---|
 | 83 |     for (i[1]=0; i[1]<deg_1; ++i[1])
 | 
|---|
 | 84 |       _compute_coefficients_1d(i, 2);
 | 
|---|
 | 85 | }
 | 
|---|
 | 86 | 
 | 
|---|
 | 87 | void Particle::Interpolation::_compute_coefficients_1d(const Index& index, const unsigned int& direction)
 | 
|---|
 | 88 | {
 | 
|---|
 | 89 |   vmg_float power = 1.0;
 | 
|---|
 | 90 |   unsigned long faculty = 1;
 | 
|---|
 | 91 |   int c;
 | 
|---|
 | 92 |   Index i;
 | 
|---|
 | 93 | 
 | 
|---|
 | 94 |   for (i=index, c=0; c<deg_1; ++i[direction], ++c)
 | 
|---|
 | 95 |     coeff_buffer[c] = _access_coeff(i);
 | 
|---|
 | 96 | 
 | 
|---|
 | 97 |   i=index;
 | 
|---|
 | 98 |   ++i[direction];
 | 
|---|
 | 99 |   for (c=1; c<deg_1; ++i[direction], ++c) {
 | 
|---|
 | 100 |     for (int j=0; j<deg_1-c; ++j)
 | 
|---|
 | 101 |       coeff_buffer[j] = coeff_buffer[j+1] - coeff_buffer[j];
 | 
|---|
 | 102 |     faculty *= c;
 | 
|---|
 | 103 |     power *= h[direction];
 | 
|---|
 | 104 |     _access_coeff(i) = coeff_buffer[0] / (faculty*power);
 | 
|---|
 | 105 |   }
 | 
|---|
 | 106 | }
 | 
|---|
 | 107 | 
 | 
|---|
 | 108 | void Particle::Interpolation::Evaluate(Particle& p)
 | 
|---|
 | 109 | {
 | 
|---|
 | 110 |   const Vector& pos = p.Pos();
 | 
|---|
 | 111 |   vmg_float& pot = p.Pot();
 | 
|---|
 | 112 |   Vector& field = p.Field();
 | 
|---|
 | 113 | 
 | 
|---|
 | 114 |   pot = 0.0;
 | 
|---|
 | 115 |   field = 0.0;
 | 
|---|
 | 116 | 
 | 
|---|
 | 117 |   Vector offset = pos - pos_begin;
 | 
|---|
 | 118 |   buffer[0] = 1.0;
 | 
|---|
 | 119 |   for (int i=0; i<deg; ++i) {
 | 
|---|
 | 120 |     buffer[i+1] = buffer[i] * offset;
 | 
|---|
 | 121 |     for (int j=0; j<i; ++j)
 | 
|---|
 | 122 |       buffer_diff[i][j] = buffer_diff[i-1][j] * offset;
 | 
|---|
 | 123 |     buffer_diff[i][i] = buffer[i];
 | 
|---|
 | 124 |     offset -= h;
 | 
|---|
 | 125 |   }
 | 
|---|
 | 126 | 
 | 
|---|
 | 127 |   for (int i=1; i<deg; ++i)
 | 
|---|
 | 128 |     for (int j=1; j<=i; ++j)
 | 
|---|
 | 129 |       buffer_diff[i][0] += buffer_diff[i][j];
 | 
|---|
 | 130 | 
 | 
|---|
 | 131 |   for (int i=0; i<deg_1; ++i)
 | 
|---|
 | 132 |     for (int j=0; j<deg_1; ++j)
 | 
|---|
 | 133 |       for (int k=0; k<deg_1; ++k)
 | 
|---|
 | 134 |         pot += _access_coeff(i,j,k) * buffer[i][0] * buffer[j][1] * buffer[k][2];
 | 
|---|
 | 135 | 
 | 
|---|
 | 136 |   for (int i=0; i<deg_1; ++i)
 | 
|---|
 | 137 |     for (int j=0; j<deg_1; ++j)
 | 
|---|
 | 138 |       for (int k=0; k<deg; ++k) {
 | 
|---|
 | 139 |         field[0] -= _access_coeff(k+1, i, j) * buffer[i][1] * buffer[j][2] * buffer_diff[k][0][0];
 | 
|---|
 | 140 |         field[1] -= _access_coeff(i, k+1, j) * buffer[i][0] * buffer[j][2] * buffer_diff[k][0][1];
 | 
|---|
 | 141 |         field[2] -= _access_coeff(i, j, k+1) * buffer[i][0] * buffer[j][1] * buffer_diff[k][0][2];
 | 
|---|
 | 142 |       }
 | 
|---|
 | 143 | }
 | 
|---|
 | 144 | 
 | 
|---|
 | 145 | vmg_float Particle::Interpolation::EvaluatePotentialLR(const Particle& p)
 | 
|---|
 | 146 | {
 | 
|---|
 | 147 |   vmg_float result = 0.0;
 | 
|---|
 | 148 |   Vector prod, offset;
 | 
|---|
 | 149 |   Index i;
 | 
|---|
 | 150 | 
 | 
|---|
 | 151 |   const Vector& pos = p.Pos();
 | 
|---|
 | 152 | 
 | 
|---|
 | 153 |   prod[0] = 1.0;
 | 
|---|
 | 154 |   offset[0] = pos[0] - pos_begin[0];
 | 
|---|
 | 155 |   for (i[0]=0; i[0]<deg_1; ++i[0]) {
 | 
|---|
 | 156 |     prod[1] = prod[0];
 | 
|---|
 | 157 |     offset[1] = pos[1] - pos_begin[1];
 | 
|---|
 | 158 |     for (i[1]=0; i[1]<deg_1; ++i[1]) {
 | 
|---|
 | 159 |       prod[2] = prod[1];
 | 
|---|
 | 160 |       offset[2] = pos[2] - pos_begin[2];
 | 
|---|
 | 161 |       for (i[2]=0; i[2]<deg_1; ++i[2]) {
 | 
|---|
 | 162 |         result += _access_coeff(i) * prod[2];
 | 
|---|
 | 163 |         prod[2] *= offset[2];
 | 
|---|
 | 164 |         offset[2] -= h[2];
 | 
|---|
 | 165 |       }
 | 
|---|
 | 166 |       prod[1] *= offset[1];
 | 
|---|
 | 167 |       offset[1] -= h[1];
 | 
|---|
 | 168 |     }
 | 
|---|
 | 169 |     prod[0] *= offset[0];
 | 
|---|
 | 170 |     offset[0] -= h[0];
 | 
|---|
 | 171 |   }
 | 
|---|
 | 172 | 
 | 
|---|
 | 173 |   return result;
 | 
|---|
 | 174 | }
 | 
|---|