blob: ed91025af0d20d88fd40db4baab5a3dc52cb7311 [file] [log] [blame]
/*
* QCS.cc
*
* Created on: Feb 21, 2012
* Author: cferenba
*
* Copyright (c) 2012, Los Alamos National Security, LLC.
* All rights reserved.
* Use of this source code is governed by a BSD-style open-source
* license; see top-level LICENSE file for full license text.
*/
#include "QCS.hh"
#include <cmath>
#include "Memory.hh"
#include "InputFile.hh"
#include "Vec2.hh"
#include "Mesh.hh"
#include "Hydro.hh"
using namespace std;
QCS::QCS(const InputFile* inp, Hydro* h) : hydro(h) {
qgamma = inp->getDouble("qgamma", 5. / 3.);
q1 = inp->getDouble("q1", 0.);
q2 = inp->getDouble("q2", 2.);
}
QCS::~QCS() {}
void QCS::calcForce(
double2* sf,
const int sfirst,
const int slast) {
int cfirst = sfirst;
int clast = slast;
// declare temporary variables
double* c0area = Memory::alloc<double>(clast - cfirst);
double* c0evol = Memory::alloc<double>(clast - cfirst);
double* c0du = Memory::alloc<double>(clast - cfirst);
double* c0div = Memory::alloc<double>(clast - cfirst);
double* c0cos = Memory::alloc<double>(clast - cfirst);
double2* c0qe = Memory::alloc<double2>(2 * (clast - cfirst));
// [1] Find the right, left, top, bottom edges to use for the
// limiters
// *** NOT IMPLEMENTED IN PENNANT ***
// [2] Compute corner divergence and related quantities
// [2.1] Find the corner divergence
// [2.2] Compute the cos angle for c
// [2.3] Find the evolution factor c0evol(c) and the Delta u(c) = du(c)
// [2.4] Find the weights c0w(c)
setCornerDiv(c0area, c0div, c0evol, c0du, c0cos, sfirst, slast);
// [3] Find the limiters Psi(c)
// *** NOT IMPLEMENTED IN PENNANT ***
// [4] Compute the Q vector (corner based)
// [4.1] Compute cmu = (1-psi) . crho . zKUR . c0evol
// [4.2] Compute the q vector associated with c on edges
// e1=[n0,n1], e2=[n1,n2]
// c0qe(2,c) = cmu(c).( u(n2)-u(n1) ) / l_{n1->n2}
// c0qe(1,c) = cmu(c).( u(n1)-u(n0) ) / l_{n0->n1}
setQCnForce(c0div, c0du, c0evol, c0qe, sfirst, slast);
// [5] Compute the Q forces
setForce(c0area, c0qe, c0cos, sf, sfirst, slast);
// [6] Set velocity difference to use to compute timestep
setVelDiff(sfirst, slast);
Memory::free(c0area);
Memory::free(c0evol);
Memory::free(c0du);
Memory::free(c0div);
Memory::free(c0cos);
Memory::free(c0qe);
}
// Routine number [2] in the full algorithm
// [2.1] Find the corner divergence
// [2.2] Compute the cos angle for c
// [2.3] Find the evolution factor c0evol(c)
// and the Delta u(c) = du(c)
void QCS::setCornerDiv(
double* c0area,
double* c0div,
double* c0evol,
double* c0du,
double* c0cos,
const int sfirst,
const int slast) {
const Mesh* mesh = hydro->mesh;
const int nums = mesh->nums;
const int numz = mesh->numz;
const double2* pu = hydro->pu;
const double2* px = mesh->pxp;
const double2* ex = mesh->exp;
const double2* zx = mesh->zxp;
const double* elen = mesh->elen;
const int* znump = mesh->znump;
int cfirst = sfirst;
int clast = slast;
int zfirst = mesh->mapsz[sfirst];
int zlast = (slast < nums ? mesh->mapsz[slast] : numz);
double2* z0uc = Memory::alloc<double2>(zlast - zfirst);
double2 up0, up1, up2, up3;
double2 xp0, xp1, xp2, xp3;
// [1] Compute a zone-centered velocity
fill(&z0uc[0], &z0uc[zlast-zfirst], double2(0., 0.));
for (int c = cfirst; c < clast; ++c) {
int p = mesh->mapsp1[c];
int z = mesh->mapsz[c];
int z0 = z - zfirst;
z0uc[z0] += pu[p];
}
for (int z = zfirst; z < zlast; ++z) {
int z0 = z - zfirst;
z0uc[z0] /= (double) znump[z];
}
// [2] Divergence at the corner
#pragma ivdep
for (int c = cfirst; c < clast; ++c) {
int s2 = c;
int s = mesh->mapss3[s2];
// Associated zone, corner, point
int z = mesh->mapsz[s];
int z0 = z - zfirst;
int c0 = c - cfirst;
int p = mesh->mapsp2[s];
// Points
int p1 = mesh->mapsp1[s];
int p2 = mesh->mapsp2[s2];
// Edges
int e1 = mesh->mapse[s];
int e2 = mesh->mapse[s2];
// Velocities and positions
// 0 = point p
up0 = pu[p];
xp0 = px[p];
// 1 = edge e2
up1 = 0.5 * (pu[p] + pu[p2]);
xp1 = ex[e2];
// 2 = zone center z
up2 = z0uc[z0];
xp2 = zx[z];
// 3 = edge e1
up3 = 0.5 * (pu[p1] + pu[p]);
xp3 = ex[e1];
// compute 2d cartesian volume of corner
double cvolume = 0.5 * cross(xp2 - xp0, xp3 - xp1);
c0area[c0] = cvolume;
// compute cosine angle
double2 v1 = xp3 - xp0;
double2 v2 = xp1 - xp0;
double de1 = elen[e1];
double de2 = elen[e2];
double minelen = min(de1, de2);
c0cos[c0] = ((minelen < 1.e-12) ?
0. :
4. * dot(v1, v2) / (de1 * de2));
// compute divergence of corner
c0div[c0] = (cross(up2 - up0, xp3 - xp1) -
cross(up3 - up1, xp2 - xp0)) /
(2.0 * cvolume);
// compute evolution factor
double2 dxx1 = 0.5 * (xp1 + xp2 - xp0 - xp3);
double2 dxx2 = 0.5 * (xp2 + xp3 - xp0 - xp1);
double dx1 = length(dxx1);
double dx2 = length(dxx2);
// average corner-centered velocity
double2 duav = 0.25 * (up0 + up1 + up2 + up3);
double test1 = abs(dot(dxx1, duav) * dx2);
double test2 = abs(dot(dxx2, duav) * dx1);
double num = (test1 > test2 ? dx1 : dx2);
double den = (test1 > test2 ? dx2 : dx1);
double r = num / den;
double evol = sqrt(4.0 * cvolume * r);
evol = min(evol, 2.0 * minelen);
// compute delta velocity
double dv1 = length2(up1 + up2 - up0 - up3);
double dv2 = length2(up2 + up3 - up0 - up1);
double du = sqrt(max(dv1, dv2));
c0evol[c0] = (c0div[c0] < 0.0 ? evol : 0.);
c0du[c0] = (c0div[c0] < 0.0 ? du : 0.);
} // for s
Memory::free(z0uc);
}
// Routine number [4] in the full algorithm CS2DQforce(...)
void QCS::setQCnForce(
const double* c0div,
const double* c0du,
const double* c0evol,
double2* c0qe,
const int sfirst,
const int slast) {
const Mesh* mesh = hydro->mesh;
const double2* pu = hydro->pu;
const double* zrp = hydro->zrp;
const double* zss = hydro->zss;
const double* elen = mesh->elen;
int cfirst = sfirst;
int clast = slast;
double* c0rmu = Memory::alloc<double>(clast - cfirst);
const double gammap1 = qgamma + 1.0;
// [4.1] Compute the c0rmu (real Kurapatenko viscous scalar)
#pragma ivdep
for (int c = cfirst; c < clast; ++c) {
int c0 = c - cfirst;
int z = mesh->mapsz[c];
// Kurapatenko form of the viscosity
double ztmp2 = q2 * 0.25 * gammap1 * c0du[c0];
double ztmp1 = q1 * zss[z];
double zkur = ztmp2 + sqrt(ztmp2 * ztmp2 + ztmp1 * ztmp1);
// Compute c0rmu for each corner
double rmu = zkur * zrp[z] * c0evol[c0];
c0rmu[c0] = ((c0div[c0] > 0.0) ? 0. : rmu);
} // for c
// [4.2] Compute the c0qe for each corner
#pragma ivdep
for (int c = cfirst; c < clast; ++c) {
int s4 = c;
int s = mesh->mapss3[s4];
int c0 = c - cfirst;
int p = mesh->mapsp2[s];
// Associated point and edge 1
int p1 = mesh->mapsp1[s];
int e1 = mesh->mapse[s];
// Associated point and edge 2
int p2 = mesh->mapsp2[s4];
int e2 = mesh->mapse[s4];
// Compute: c0qe(1,2,3)=edge 1, y component (2nd), 3rd corner
// c0qe(2,1,3)=edge 2, x component (1st)
c0qe[2 * c0] = c0rmu[c0] * (pu[p] - pu[p1]) / elen[e1];
c0qe[2 * c0 + 1] = c0rmu[c0] * (pu[p2] - pu[p]) / elen[e2];
} // for s
Memory::free(c0rmu);
}
// Routine number [5] in the full algorithm CS2DQforce(...)
void QCS::setForce(
const double* c0area,
const double2* c0qe,
double* c0cos,
double2* sfq,
const int sfirst,
const int slast) {
const Mesh* mesh = hydro->mesh;
const double* elen = mesh->elen;
int cfirst = sfirst;
int clast = slast;
double* c0w = Memory::alloc<double>(clast - cfirst);
// [5.1] Preparation of extra variables
#pragma ivdep
for (int c = cfirst; c < clast; ++c) {
int c0 = c - cfirst;
double csin2 = 1.0 - c0cos[c0] * c0cos[c0];
c0w[c0] = ((csin2 < 1.e-4) ? 0. : c0area[c0] / csin2);
c0cos[c0] = ((csin2 < 1.e-4) ? 0. : c0cos[c0]);
} // for c
// [5.2] Set-Up the forces on corners
#pragma ivdep
for (int s = sfirst; s < slast; ++s) {
// Associated corners 1 and 2, and edge
int c1 = s;
int c10 = c1 - cfirst;
int c2 = mesh->mapss4[s];
int c20 = c2 - cfirst;
int e = mesh->mapse[s];
// Edge length for c1, c2 contribution to s
double el = elen[e];
sfq[s] = (c0w[c10] * (c0qe[2*c10+1] + c0cos[c10] * c0qe[2*c10]) +
c0w[c20] * (c0qe[2*c20] + c0cos[c20] * c0qe[2*c20+1]))
/ el;
} // for s
Memory::free(c0w);
}
// Routine number [6] in the full algorithm
void QCS::setVelDiff(
const int sfirst,
const int slast) {
const Mesh* mesh = hydro->mesh;
const int nums = mesh->nums;
const int numz = mesh->numz;
int zfirst = mesh->mapsz[sfirst];
int zlast = (slast < nums ? mesh->mapsz[slast] : numz);
const double2* px = mesh->pxp;
const double2* pu = hydro->pu;
const double* zss = hydro->zss;
double* zdu = hydro->zdu;
const double* elen = mesh->elen;
double* z0tmp = Memory::alloc<double>(zlast - zfirst);
fill(&z0tmp[0], &z0tmp[zlast-zfirst], 0.);
for (int s = sfirst; s < slast; ++s) {
int p1 = mesh->mapsp1[s];
int p2 = mesh->mapsp2[s];
int z = mesh->mapsz[s];
int e = mesh->mapse[s];
int z0 = z - zfirst;
double2 dx = px[p2] - px[p1];
double2 du = pu[p2] - pu[p1];
double lenx = elen[e];
double dux = dot(du, dx);
dux = (lenx > 0. ? abs(dux) / lenx : 0.);
z0tmp[z0] = max(z0tmp[z0], dux);
}
for (int z = zfirst; z < zlast; ++z) {
int z0 = z - zfirst;
zdu[z] = q1 * zss[z] + 2. * q2 * z0tmp[z0];
}
Memory::free(z0tmp);
}