Program Listing for File computemesh.cpp#
↰ Return to documentation for file (pymembrane/cppmodule/src/compute/computemesh.cpp
)
#include "computemesh.hpp"
#include "../system/systemclass.hpp"
#include "../evolver/evolverclass.hpp"
#include "../mesh/computegeometry.hpp"
void compute_edge_cotangents_fn(const int Numedges,
HE_EdgeProp *edges,
HE_VertexProp *vertices,
const HE_FaceProp *__restrict__ faces,
const BoxType _box,
const bool COMPUTEVERTEXNORMALS)
{
for (int edge_index = 0;
edge_index < Numedges;
edge_index++)
{
real cot_alpha = 0.0;
real cot_beta = 0.0;
if (edges[edge_index].boundary == false)
{
int v0 = edges[edge_index].v0;
int v1 = edges[edge_index].v1;
int v2 = edges[edge_index].v2;
int v3 = edges[edge_index].v3;
real3 r0 = vertices[v0].r;
real3 r1 = vertices[v1].r;
real3 r2 = vertices[v2].r;
real3 r3 = vertices[v3].r;
real3 r10, r12, r30, r32;
r10 = pymemb::vector_subtract(r0, r1, _box);
r12 = pymemb::vector_subtract(r2, r1, _box);
r30 = pymemb::vector_subtract(r0, r3, _box);
r32 = pymemb::vector_subtract(r2, r3, _box);
real r10_dot_r12 = vdot(r10, r12);
real3 vec_r10_cross_r12;
vcross(vec_r10_cross_r12, r12, r10);
real r10_cross_r12 = sqrt(vdot(vec_r10_cross_r12, vec_r10_cross_r12));
cot_alpha = r10_dot_r12 / r10_cross_r12;
real r30_dot_r32 = vdot(r30, r32);
real3 vec_r30_cross_r32;
vcross(vec_r30_cross_r32, r30, r32);
real r30_cross_r32 = sqrt(vdot(vec_r30_cross_r32, vec_r30_cross_r32));
cot_beta = r30_dot_r32 / r30_cross_r32;
}
else
{
int v0 = edges[edge_index].v0;
int v1 = edges[edge_index].v1;
int v2 = edges[edge_index].v2;
int v3 = edges[edge_index].v3;
int face_index = edges[edge_index].face_k;
if (edges[edge_index].face_l > 0)
face_index = edges[edge_index].face_l;
int v;
if (faces[face_index].v1 == v1)
v = v1;
else if (faces[face_index].v2 == v1)
v = v1;
else if (faces[face_index].v3 == v1)
v = v1;
else if (faces[face_index].v1 == v3)
v = v3;
else if (faces[face_index].v2 == v3)
v = v3;
else if (faces[face_index].v3 == v3)
v = v3;
real3 r0 = vertices[v0].r;
real3 r1 = vertices[v].r;
real3 r2 = vertices[v2].r;
real3 r10, r12;
r10 = pymemb::vector_subtract(r0, r1, _box);
r12 = pymemb::vector_subtract(r2, r1, _box);
real r10_dot_r12 = vdot(r10, r12);
real3 vec_r10_cross_r12;
vcross(vec_r10_cross_r12, r12, r10);
real r10_cross_r12 = sqrt(vdot(vec_r10_cross_r12, vec_r10_cross_r12));
cot_alpha = r10_dot_r12 / r10_cross_r12;
}
edges[edge_index]._property.cot_alpha = cot_alpha;
edges[edge_index]._property.cot_beta = cot_beta;
// sum the the cotangent to i vertex
if (COMPUTEVERTEXNORMALS)
{
real3 rij;
rij = pymemb::vector_subtract(vertices[edges[edge_index].j].r, vertices[edges[edge_index].i].r, _box);
vertices[edges[edge_index].i].normal.x += (cot_alpha + cot_beta) * rij.x;
vertices[edges[edge_index].i].normal.y += (cot_alpha + cot_beta) * rij.y;
vertices[edges[edge_index].i].normal.z += (cot_alpha + cot_beta) * rij.z;
vertices[edges[edge_index].j].normal.x += -(cot_alpha + cot_beta) * rij.x;
vertices[edges[edge_index].j].normal.y += -(cot_alpha + cot_beta) * rij.y;
vertices[edges[edge_index].j].normal.z += -(cot_alpha + cot_beta) * rij.z;
}
}
}
/*
@brief compute the face normals
*/
void compute_face_normals_fn(const int Numfaces,
HE_FaceProp *faces,
HE_VertexProp *vertices,
const BoxType _box,
const bool COMPUTEVERTEXNORMALS,
const bool AREAWeighted)
{
for (int face_index = 0;
face_index < Numfaces;
face_index++)
{
int v1 = faces[face_index].v1;
int v2 = faces[face_index].v2;
int v3 = faces[face_index].v3;
// compute
real3 face_normal = pymemb::compute_normal_triangle(vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);
faces[face_index].normal = face_normal;
if (COMPUTEVERTEXNORMALS)
{
real face_area_factor[3] = {1.0, 1.0, 1.0};
if (AREAWeighted)
{
face_area_factor[0] = pymemb::compute_area_triangle_from_vertex(vertices[v1].r, vertices[v2].r, vertices[v3].r, _box) / 3.0;
face_area_factor[1] = face_area_factor[0];
face_area_factor[2] = face_area_factor[0];
}
else
{
face_area_factor[0] = pymemb::compute_angle_vertex(vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);
face_area_factor[1] = pymemb::compute_angle_vertex(vertices[v2].r, vertices[v3].r, vertices[v1].r, _box);
face_area_factor[2] = pymemb::compute_angle_vertex(vertices[v3].r, vertices[v1].r, vertices[v2].r, _box);
}
// v1
vertices[v1].normal.x += face_area_factor[0] * face_normal.x;
vertices[v1].normal.y += face_area_factor[0] * face_normal.y;
vertices[v1].normal.z += face_area_factor[0] * face_normal.z;
// v2
vertices[v2].normal.x += face_area_factor[1] * face_normal.x;
vertices[v2].normal.y += face_area_factor[1] * face_normal.y;
vertices[v2].normal.z += face_area_factor[1] * face_normal.z;
// v3
vertices[v3].normal.x += face_area_factor[2] * face_normal.x;
vertices[v3].normal.y += face_area_factor[2] * face_normal.y;
vertices[v3].normal.z += face_area_factor[2] * face_normal.z;
}
}
}
void ComputeMesh::compute_vertex_normals(bool vertex_normal_angle_weight)
{
compute_face_normals_fn(_system.Numfaces,
&_system.faces[0],
&_system.vertices[0],
_system.get_box(),
true,
vertex_normal_angle_weight);
}
pymemb::vector<real> ComputeMesh::compute_vertex_area(void)
{
pymemb::vector<real> vertex_area(_system.Numvertices, 0.0);
for (int face_index = 0;
face_index < _system.Numfaces;
face_index++)
{
int v1 = _system.faces[face_index].v1;
int v2 = _system.faces[face_index].v2;
int v3 = _system.faces[face_index].v3;
// compute
auto face_area = pymemb::compute_area_triangle_from_vertex(_system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r, _system.get_box()) / 3.0;
// v1
vertex_area[v1] += face_area;
// v2
vertex_area[v2] += face_area;
// v3
vertex_area[v3] += face_area;
}
return vertex_area;
}
void ComputeMesh::compute_face_normals(void)
{
compute_face_normals_fn(_system.Numfaces,
&_system.faces[0],
&_system.vertices[0],
_system.get_box(),
false,
false);
}
void compute_edge_length_fn(const int Numedges,
const HE_EdgeProp *__restrict__ edges,
const HE_VertexProp *__restrict__ vertices,
real *edge_lengths,
const BoxType _box)
{
for (int edge_index = 0;
edge_index < Numedges;
edge_index++)
{
auto rij = pymemb::vector_subtract(vertices[edges[edge_index].i].r, vertices[edges[edge_index].j].r, _box);
edge_lengths[edge_index] = sqrt(vdot(rij, rij));
}
}
pymemb::vector<real> ComputeMesh::compute_edge_lengths(void)
{
pymemb::vector<real> edge_lengths(_system.Numedges, 0.0);
compute_edge_length_fn(_system.Numedges,
&_system.edges[0],
&_system.vertices[0],
&edge_lengths[0],
_system.get_box());
return (pymemb::copy(edge_lengths));
}
real ComputeMesh::gaussiancurvature_vertex(const int &vertex_index)
{
real3 r0 = _system.vertices[vertex_index].r;
int first_he = _system.vertices[vertex_index]._hedge;
int he = first_he;
double phi = 0.0;
do
{
int he_prev = _system.halfedges[he].prev;
int v1_to = _system.halfedges[he].vert_to;
real3 r1 = _system.vertices[v1_to].r;
int v2_to = _system.halfedges[he_prev].vert_from;
real3 r2 = _system.vertices[v2_to].r;
real3 r10, r20;
r10 = pymemb::vector_subtract(r1, r0, _system.get_box());
r20 = pymemb::vector_subtract(r2, r0, _system.get_box());
double r10_norm = sqrt(vdot(r10, r10));
double r20_norm = sqrt(vdot(r20, r20));
aXvec((1.0 / r10_norm), r10);
aXvec((1.0 / r20_norm), r20);
r10_norm = sqrt(vdot(r10, r10));
r20_norm = sqrt(vdot(r20, r20));
double r10_dot_r20 = vdot(r10, r20);
if (r10_dot_r20 > 1.0)
r10_dot_r20 = 1.0;
else if (r10_dot_r20 < -1.0)
r10_dot_r20 = -1.0;
phi += acos(r10_dot_r20);
he = _system.halfedges[he_prev].pair;
} while (he != first_he);
if (_system.vertices[vertex_index].boundary == false)
return (2.0 * M_PI - phi);
// double check this
else if (phi > M_PI)
return (phi - M_PI);
//else
// return (phi + M_PI);
}
real ComputeMesh::meancurvature_vertex(const int &vertex_index)
{
real3 sigma, nv, nf;
nv.x = nv.y = nv.z = 0.0;
sigma.x = sigma.y = sigma.z = 0.0;
double vertex_area = 0.0;
int v0 = vertex_index, v1, v2;
int he = _system.vertices[vertex_index]._hedge;
int first = he;
do
{
// DO SOMETHING WITH THAT EDGE
int edge_index = _system.halfedges[he].edge;
if (_system.edges[edge_index].boundary == false)
{
v1 = _system.halfedges[he].vert_to;
//
int he_next = _system.halfedges[he].next;
//
v2 = _system.halfedges[he_next].vert_to;
nf = pymemb::compute_normal_triangle(_system.vertices[v0].r, _system.vertices[v1].r, _system.vertices[v2].r, _system.get_box());
nv.x += nf.x;
nv.y += nf.y;
nv.z += nf.z;
real3 r0 = _system.vertices[v0].r;
real3 r1 = _system.vertices[v1].r;
real3 r2 = _system.vertices[v2].r;
real3 r01, r02, r10, r12, r20, r21;
r01 = pymemb::vector_subtract(r1, r0, _system.get_box());
r02 = pymemb::vector_subtract(r2, r0, _system.get_box());
r10 = pymemb::vector_subtract(r0, r1, _system.get_box());
r12 = pymemb::vector_subtract(r2, r1, _system.get_box());
r20 = pymemb::vector_subtract(r0, r2, _system.get_box());
r21 = pymemb::vector_subtract(r1, r2, _system.get_box());
double r01_dot_r02 = vdot(r01, r02);
double r10_dot_r12 = vdot(r10, r12);
double r20_dot_r21 = vdot(r20, r21);
real3 r01_cross_r02, r10_cross_r12, r20_cross_r21;
vcross(r01_cross_r02, r01, r02);
vcross(r10_cross_r12, r10, r12);
vcross(r20_cross_r21, r21, r20);
double r01_cross_r02n = sqrt(vdot(r01_cross_r02, r01_cross_r02));
double r10_cross_r12n = sqrt(vdot(r10_cross_r12, r10_cross_r12));
double r20_cross_r21n = sqrt(vdot(r20_cross_r21, r20_cross_r21));
double cot_alpha = r10_dot_r12 / r10_cross_r12n;
double cot_beta = r20_dot_r21 / r20_cross_r21n;
double cot_weight = 0.5 * (cot_alpha + cot_beta);
sigma.x += 0.5 * cot_alpha * r02.x + 0.5 * cot_beta * r01.x;
sigma.y += 0.5 * cot_alpha * r02.y + 0.5 * cot_beta * r01.y;
sigma.z += 0.5 * cot_alpha * r02.z + 0.5 * cot_beta * r01.z;
if (r01_dot_r02 < 0 || r10_dot_r12 < 0 || r20_dot_r21 < 0)
{
if (r01_dot_r02 < 0)
vertex_area += 0.5 * r01_cross_r02n;
else
vertex_area += 0.25 * r01_cross_r02n;
}
else
vertex_area += 0.125 * vdot(r02, r02) * cot_alpha + 0.125 * vdot(r01, r01) * cot_beta;
}
/*------------------------------------------------*/
// MOVE TO THE NEXT EDGE
int he_pair = _system.halfedges[he].pair;
he = _system.halfedges[he_pair].next;
} while ((he != first));
double sign = (vdot(nv, sigma) > 0.) ? -1. : 1.;
double H = sign * sqrt(vdot(sigma, sigma)) / vertex_area;
return H;
}
pymemb::vector<real> ComputeMesh::gaussiancurvature(void)
{
std::vector<double> curv;
for (int vertex_index = 0; vertex_index < _system.Numvertices; vertex_index++)
{
curv.push_back(this->gaussiancurvature_vertex(vertex_index));
}
return (curv);
}
pymemb::vector<real> ComputeMesh::meancurvature(void)
{
std::vector<double> curv;
for (int vertex_index = 0; vertex_index < _system.Numvertices; vertex_index++)
{
curv.push_back(this->meancurvature_vertex(vertex_index));
}
// Deal with the boundaries
// Average the vertex curvature of the neighbors of the boundary vertex
// and assign it to the boundary vertex
for (int vertex_index = 0; vertex_index < _system.Numvertices; vertex_index++)
{
curv.push_back(this->meancurvature_vertex(vertex_index));
if (_system.vertices[vertex_index].boundary == true)
{
curv[vertex_index] = 0.0;
int count = 0;
int he = _system.vertices[vertex_index]._hedge;
int first = he;
do
{
int he_pair = _system.halfedges[he].pair;
int v1 = _system.halfedges[he].vert_to;
int v2 = _system.halfedges[he_pair].vert_to;
if (_system.vertices[v1].boundary == false)
{
curv[vertex_index] += curv[v1];
count++;
}
if (_system.vertices[v2].boundary == false)
{
curv[vertex_index] += curv[v2];
count++;
}
he = _system.halfedges[he_pair].next;
} while ((he != first));
curv[vertex_index] /= count;
}
}
return (curv);
}
std::map<std::string, pymemb::vector<real>> ComputeMesh::compute_mesh_curvature(void)
{
std::map<std::string, pymemb::vector<real>> curvature;
pymemb::vector<real> K;
pymemb::vector<real> H;
pymemb::vector<int> boundary_vertices;
for (int vertex_index = 0; vertex_index < _system.Numvertices; vertex_index++)
{
K.push_back(this->gaussiancurvature_vertex(vertex_index));
H.push_back(this->meancurvature_vertex(vertex_index));
if (_system.vertices[vertex_index].boundary == true)
boundary_vertices.push_back(vertex_index);
}
// Deal with the boundaries
// Average the vertex curvature of the neighbors of the boundary vertex
// and assign it to the boundary vertex
for (const auto &bvertex : boundary_vertices)
{
H[bvertex] = 0.0;
int count = 0;
int he = _system.vertices[bvertex]._hedge;
int first = he;
do
{
int he_pair = _system.halfedges[he].pair;
int v1 = _system.halfedges[he].vert_to;
int v2 = _system.halfedges[he_pair].vert_to;
if (_system.vertices[v1].boundary == false)
{
H[bvertex] += H[v1];
count++;
}
if (_system.vertices[v2].boundary == false)
{
H[bvertex] += H[v2];
count++;
}
he = _system.halfedges[he_pair].next;
} while ((he != first));
H[bvertex] /= count;
}
// save the curvatures
curvature["gaussian"] = K;
curvature["mean"] = H;
return curvature;
}
real ComputeMesh::compute_mesh_volume(void)
{
real mesh_volume = 0.0;
if (_system.close_surface == true)
{
for (int face_index = 0; face_index < _system.faces.size(); face_index++)
{
real3 r0 = _system.vertices[_system.faces[face_index].v1].r;
real3 r1 = _system.vertices[_system.faces[face_index].v2].r;
real3 r2 = _system.vertices[_system.faces[face_index].v3].r;
real3 nt = pymemb::compute_normal_triangle(r0, r1, r2, _system.get_box());
mesh_volume += vdot(r0, nt) / 6.0;
}
}
else
{
std::cerr << "open surface doesn't have any volume\n";
}
return mesh_volume;
}
pymemb::vector<real> ComputeMesh::compute_face_area(void)
{
pymemb::vector<real> face_area;
for (int face_index = 0;
face_index < _system.Numfaces;
face_index++)
{
int v1 = _system.faces[face_index].v1;
int v2 = _system.faces[face_index].v2;
int v3 = _system.faces[face_index].v3;
face_area.push_back(pymemb::compute_area_triangle_from_vertex(_system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r, _system.get_box()));
}
return face_area;
}
real ComputeMesh::compute_mesh_area(void)
{
real mesh_area = 0.0;
for (int face_index = 0;
face_index < _system.Numfaces;
face_index++)
{
int v1 = _system.faces[face_index].v1;
int v2 = _system.faces[face_index].v2;
int v3 = _system.faces[face_index].v3;
mesh_area += pymemb::compute_area_triangle_from_vertex(_system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r, _system.get_box());
}
return mesh_area;
}
pymemb::vector<pymemb::vector<real>> ComputeMesh::compute_face_metric(void)
{
pymemb::vector<pymemb::vector<real>> metrics;
for (int face_index = 0;
face_index < _system.Numfaces;
face_index++)
{
int v1 = _system.faces[face_index].v1;
int v2 = _system.faces[face_index].v2;
int v3 = _system.faces[face_index].v3;
pymemb::vector<real> g_now(3);
pymemb::compute_form_factor_triangle(&g_now[0], _system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r, _system.get_box());
metrics.push_back(g_now);
}
return metrics;
}
std::map<std::string, real> ComputeMesh::compute_mesh_energy(EvolverClass &evolver)
{
evolver.reset_mesh_energy();
evolver.compute_mesh_energy();
auto v_energy = 0.0;
auto e_energy = 0.0;
auto f_energy = 0.0;
for (auto v : _system.vertices)
v_energy += v.energy;
for (auto e : _system.edges)
e_energy += e.energy;
for (auto f : _system.faces)
f_energy += f.energy;
std::map<std::string, real> val;
val["vertices"] = v_energy;
val["edges"] = e_energy;
val["faces"] = f_energy;
return val;
}
pymemb::vector<real3> ComputeMesh::compute_vertex_forces(EvolverClass &evolver)
{
evolver.reset_mesh_forces();
evolver.compute_mesh_forces();
auto vertices = _system.get_vertices();
pymemb::vector<real3> forces(vertices.size());
for (auto v : vertices)
forces[v.id] = v.forceC;
return forces;
}
realTensor ComputeMesh::compute_stresses(EvolverClass &evolver, const bool &include_velocities)
{
evolver.reset_mesh_stresses();
evolver.compute_mesh_stresses();
return (this->get_stresses(evolver, include_velocities));
}
realTensor ComputeMesh::get_stresses(EvolverClass &evolver, const bool &include_velocities)
{
realTensor zeroTensor;
zeroTensor.xx = 0.0;
zeroTensor.xy = 0.0;
zeroTensor.xz = 0.0;
zeroTensor.yx = 0.0;
zeroTensor.yy = 0.0;
zeroTensor.yz = 0.0;
zeroTensor.zx = 0.0;
zeroTensor.zy = 0.0;
zeroTensor.zz = 0.0;
realTensor total_stress = zeroTensor;
if (evolver.has_vertex_forces == true)
{
auto stress_group = pymemb::copy(_system.stress_group_vertices);
for (auto vertex_index = 0; vertex_index < _system.Numvertices; vertex_index++)
{
total_stress.xx += stress_group[vertex_index].xx;
total_stress.xy += stress_group[vertex_index].xy;
total_stress.xz += stress_group[vertex_index].xz;
total_stress.yx += stress_group[vertex_index].yx;
total_stress.yy += stress_group[vertex_index].yy;
total_stress.yz += stress_group[vertex_index].yz;
total_stress.zx += stress_group[vertex_index].zx;
total_stress.zy += stress_group[vertex_index].zy;
total_stress.zz += stress_group[vertex_index].zz;
}
}
if (evolver.has_edge_forces == true)
{
auto stress_group = pymemb::copy(_system.stress_group_edges);
for (auto edge_index = 0; edge_index < _system.Numedges; edge_index++)
{
total_stress.xx += stress_group[edge_index].xx;
total_stress.xy += stress_group[edge_index].xy;
total_stress.xz += stress_group[edge_index].xz;
total_stress.yx += stress_group[edge_index].yx;
total_stress.yy += stress_group[edge_index].yy;
total_stress.yz += stress_group[edge_index].yz;
total_stress.zx += stress_group[edge_index].zx;
total_stress.zy += stress_group[edge_index].zy;
total_stress.zz += stress_group[edge_index].zz;
}
}
if (evolver.has_face_forces == true)
{
auto stress_group = pymemb::copy(_system.stress_group_faces);
for (auto face_index = 0; face_index < _system.Numfaces; face_index++)
{
total_stress.xx += stress_group[face_index].xx;
total_stress.xy += stress_group[face_index].xy;
total_stress.xz += stress_group[face_index].xz;
total_stress.yx += stress_group[face_index].yx;
total_stress.yy += stress_group[face_index].yy;
total_stress.yz += stress_group[face_index].yz;
total_stress.zx += stress_group[face_index].zx;
total_stress.zy += stress_group[face_index].zy;
total_stress.zz += stress_group[face_index].zz;
}
}
if (include_velocities == true)
{
auto kinetic_energy_tensor = this->compute_kinetic_energy_tensor();
total_stress.xx += kinetic_energy_tensor.xx;
total_stress.xy += kinetic_energy_tensor.xy;
total_stress.xz += kinetic_energy_tensor.xz;
total_stress.yx += kinetic_energy_tensor.yx;
total_stress.yy += kinetic_energy_tensor.yy;
total_stress.yz += kinetic_energy_tensor.yz;
total_stress.zx += kinetic_energy_tensor.zx;
total_stress.zy += kinetic_energy_tensor.zy;
total_stress.zz += kinetic_energy_tensor.zz;
}
total_stress.xx /= _system.Numvertices;
total_stress.xy /= _system.Numvertices;
total_stress.xz /= _system.Numvertices;
total_stress.yx /= _system.Numvertices;
total_stress.yy /= _system.Numvertices;
total_stress.yz /= _system.Numvertices;
total_stress.zx /= _system.Numvertices;
total_stress.zy /= _system.Numvertices;
total_stress.zz /= _system.Numvertices;
return (total_stress);
}
realTensor ComputeMesh::compute_kinetic_energy_tensor(void)
{
realTensor zeroTensor;
zeroTensor.xx = 0.0;
zeroTensor.xy = 0.0;
zeroTensor.xz = 0.0;
zeroTensor.yx = 0.0;
zeroTensor.yy = 0.0;
zeroTensor.yz = 0.0;
zeroTensor.zx = 0.0;
zeroTensor.zy = 0.0;
zeroTensor.zz = 0.0;
auto vertices = _system.get_vertices();
realTensor kinetic_energy_tensor = zeroTensor;
for (int vindex = 0;
vindex < _system.Numvertices;
vindex++)
{
auto vertex = vertices[vindex];
realTensor kinetic_tensor;
kinetic_energy_tensor.xx += vertex.mass * vertex.v.x * vertex.v.x;
kinetic_energy_tensor.xy += vertex.mass * vertex.v.x * vertex.v.y;
kinetic_energy_tensor.xz += vertex.mass * vertex.v.x * vertex.v.z;
kinetic_energy_tensor.yx += vertex.mass * vertex.v.y * vertex.v.x;
kinetic_energy_tensor.yy += vertex.mass * vertex.v.y * vertex.v.y;
kinetic_energy_tensor.yz += vertex.mass * vertex.v.y * vertex.v.z;
kinetic_energy_tensor.zx += vertex.mass * vertex.v.z * vertex.v.x;
kinetic_energy_tensor.zy += vertex.mass * vertex.v.z * vertex.v.y;
kinetic_energy_tensor.zz += vertex.mass * vertex.v.z * vertex.v.z;
}
return kinetic_energy_tensor;
}
real ComputeMesh::compute_kinetic_energy(void)
{
auto vertices = _system.get_vertices();
real KE = 0.0;
for (auto vertex : vertices)
{
KE += 0.5 * vertex.mass * vdot(vertex.v, vertex.v);
}
return KE;
}
real ComputeMesh::compute_temperature(void)
{
auto KE = this->compute_kinetic_energy();
real T = (2.0 / 3.0) * KE / _system.Numvertices;
// KE = ((dim/2.0) N kT)
return T;
}
std::vector<real> ComputeMesh::compute_pressure(EvolverClass &evolver)
{
auto stress = this->compute_stresses(evolver, true);
real V = 1.0; //_system.get_box_volume();
std::vector<real> P;
P.push_back(_system.Numvertices * stress.xx / V);
P.push_back(_system.Numvertices * stress.yy / V);
P.push_back(_system.Numvertices * stress.zz / V);
// auto P = (stress.xx + stress.yy + stress.zz) / (3.0 * _system.get_box_volume());
return P;
}
realTensor ComputeMesh::compute_stresses_virial(EvolverClass &evolver, const bool &include_velocities)
{
evolver.reset_mesh_atom_stresses();
evolver.compute_mesh_atom_stresses();
realTensor zeroTensor;
zeroTensor.xx = 0.0;
zeroTensor.xy = 0.0;
zeroTensor.xz = 0.0;
zeroTensor.yx = 0.0;
zeroTensor.yy = 0.0;
zeroTensor.yz = 0.0;
zeroTensor.zx = 0.0;
zeroTensor.zy = 0.0;
zeroTensor.zz = 0.0;
auto stress_virial_atom = pymemb::copy(_system.stress_virial_atom);
auto total_stress = zeroTensor;
for (auto s : stress_virial_atom)
{
total_stress.xx += s.xx;
total_stress.xy += s.xy;
total_stress.xz += s.xz;
total_stress.yx += s.yx;
total_stress.yy += s.yy;
total_stress.yz += s.yz;
total_stress.zx += s.zx;
total_stress.zy += s.zy;
total_stress.zz += s.zz;
}
// total_stress = thrust::reduce(_system.stress_virial_atom.begin(), _system.stress_virial_atom.end(), zeroTensor, pymemb::reduce_tensor<realTensor>());
if (include_velocities == true)
{
auto kinetic_energy_tensor = this->compute_kinetic_energy_tensor();
total_stress.xx += kinetic_energy_tensor.xx;
total_stress.xy += kinetic_energy_tensor.xy;
total_stress.xz += kinetic_energy_tensor.xz;
total_stress.yx += kinetic_energy_tensor.yx;
total_stress.yy += kinetic_energy_tensor.yy;
total_stress.yz += kinetic_energy_tensor.yz;
total_stress.zx += kinetic_energy_tensor.zx;
total_stress.zy += kinetic_energy_tensor.zy;
total_stress.zz += kinetic_energy_tensor.zz;
}
total_stress.xx /= _system.Numvertices;
total_stress.xy /= _system.Numvertices;
total_stress.xz /= _system.Numvertices;
total_stress.yx /= _system.Numvertices;
total_stress.yy /= _system.Numvertices;
total_stress.yz /= _system.Numvertices;
total_stress.zx /= _system.Numvertices;
total_stress.zy /= _system.Numvertices;
total_stress.zz /= _system.Numvertices;
return (total_stress);
}
std::vector<realTensor> ComputeMesh::compute_stresses_atom(EvolverClass &evolver, const bool &include_velocities)
{
evolver.reset_mesh_atom_stresses();
evolver.compute_mesh_atom_stresses();
std::vector<realTensor> stress_virial_atom = _system.stress_virial_atom;
if (include_velocities == true)
{
for (auto i = 0; i < _system.Numvertices; i++)
{
stress_virial_atom[i].xx += _system.vertices[i].mass * _system.vertices[i].v.x * _system.vertices[i].v.x;
stress_virial_atom[i].xy += _system.vertices[i].mass * _system.vertices[i].v.x * _system.vertices[i].v.y;
stress_virial_atom[i].xz += _system.vertices[i].mass * _system.vertices[i].v.x * _system.vertices[i].v.z;
stress_virial_atom[i].yx += _system.vertices[i].mass * _system.vertices[i].v.y * _system.vertices[i].v.x;
stress_virial_atom[i].yy += _system.vertices[i].mass * _system.vertices[i].v.y * _system.vertices[i].v.y;
stress_virial_atom[i].yz += _system.vertices[i].mass * _system.vertices[i].v.y * _system.vertices[i].v.z;
stress_virial_atom[i].zx += _system.vertices[i].mass * _system.vertices[i].v.z * _system.vertices[i].v.x;
stress_virial_atom[i].zy += _system.vertices[i].mass * _system.vertices[i].v.z * _system.vertices[i].v.y;
stress_virial_atom[i].zz += _system.vertices[i].mass * _system.vertices[i].v.z * _system.vertices[i].v.z;
}
}
return (stress_virial_atom);
}