add sample code m3d
This commit is contained in:
166
m3d/src/grid.cpp
Executable file
166
m3d/src/grid.cpp
Executable file
@@ -0,0 +1,166 @@
|
||||
#include "grid.h"
|
||||
|
||||
Grid::Grid (std::string node_file, std::string tet_file):
|
||||
_node_file (node_file),
|
||||
_tet_file (tet_file)
|
||||
{
|
||||
// do the job
|
||||
this->read_node();
|
||||
this->read_tet();
|
||||
}
|
||||
|
||||
|
||||
Grid::~Grid ()
|
||||
{
|
||||
// delete tets
|
||||
for(unsigned int i=0;i<(_elements.size());++i)
|
||||
if(_elements[i]!=NULL) {
|
||||
delete _elements[i]; _elements[i]=NULL;
|
||||
}
|
||||
this->_elements.clear();
|
||||
|
||||
// delete the nodes.
|
||||
for(unsigned int i=0;i<(_nodes.size());++i) {
|
||||
if(_nodes[i]!=NULL) {
|
||||
delete _nodes[i]; _nodes[i]=NULL;
|
||||
}
|
||||
}
|
||||
this->_nodes.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
get the i-th element
|
||||
*/
|
||||
Tet& Grid::get_elem (const unsigned int i)
|
||||
{
|
||||
assert (i < this->n_elems());
|
||||
assert (_elements[i] != NULL);
|
||||
return *this->_elements[i];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
read nodes or sites
|
||||
*/
|
||||
void Grid::read_node()
|
||||
{
|
||||
// Check input buffer
|
||||
std::ifstream node_stream(this->_node_file.c_str());
|
||||
assert(node_stream.good());
|
||||
|
||||
unsigned int n_nodes=0;
|
||||
node_stream >> n_nodes;
|
||||
assert(n_nodes>0);
|
||||
this->_nodes.clear();
|
||||
this->_nodes.resize(n_nodes);
|
||||
|
||||
for (unsigned int i=0; i<n_nodes; i++) {
|
||||
unsigned int node_lab=0;
|
||||
Point xyz;
|
||||
node_stream >> node_lab
|
||||
>> xyz(0) // x-coordinate value
|
||||
>> xyz(1) // y-coordinate value
|
||||
>> xyz(2); // z-coordinate value
|
||||
Node* newnode = new Node(xyz, node_lab);
|
||||
this->_nodes[i]= newnode;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
read elements and magnetization vector M
|
||||
*/
|
||||
void Grid::read_tet ()
|
||||
{
|
||||
// Check input buffer
|
||||
std::ifstream ele_stream(this->_tet_file.c_str());
|
||||
assert (ele_stream.good());
|
||||
assert (this->_nodes.size()>0);
|
||||
|
||||
unsigned int n_elems=0;
|
||||
ele_stream >> n_elems;
|
||||
assert(n_elems>0);
|
||||
this->_elements.clear();
|
||||
this->_elements.resize(n_elems);
|
||||
|
||||
for(unsigned int i=0; i<n_elems; i++) {
|
||||
unsigned int element_id;
|
||||
Node* v[4];
|
||||
ele_stream >> element_id;
|
||||
for (unsigned int j=0; j<4; j++) {
|
||||
unsigned int node_id;
|
||||
ele_stream >> node_id;
|
||||
v[j] = this->_nodes[node_id];
|
||||
}
|
||||
double mx, my, mz;
|
||||
ele_stream >> mx >> my >> mz;
|
||||
Tet* tet = new Tet(element_id, v, Point(mx,my,mz));
|
||||
this->_elements[i] = tet;
|
||||
}
|
||||
|
||||
this->_number_elems = n_elems;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::ostream& operator <<(std::ostream& os, Grid& mesh)
|
||||
{
|
||||
os << "n_nodes()=" << mesh.n_nodes()
|
||||
<< " \nn_elems()=" << mesh.n_elems()
|
||||
<< " \n";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Write the tetrahedral elements into VTk format so that
|
||||
the grid can be shown by Paraview softeware.
|
||||
|
||||
*/
|
||||
void Grid::write_out_vtk(const std::string name)
|
||||
{
|
||||
// Open the of stream
|
||||
std::ofstream vtk_mesh((name+".vtk").c_str());
|
||||
if(!vtk_mesh.good()) {
|
||||
std::cerr<<"Can not open file:\t"<<name+".vtk"
|
||||
<<std::endl;
|
||||
} else {
|
||||
vtk_mesh<<"# vtk DataFile Version 3.0\n" //File version and identifier
|
||||
<<"Zhengyong Ren\n"
|
||||
<<"ASCII\n";
|
||||
vtk_mesh<<"DATASET UNSTRUCTURED_GRID\n";
|
||||
vtk_mesh<<"\nPOINTS\t"<<this->_nodes.size()<<"\tdouble\n";
|
||||
for(unsigned int i=0; i<this->_nodes.size(); i++) {
|
||||
const Node& temp_node= (*this->_nodes[i]);
|
||||
vtk_mesh<<temp_node(0)<<"\t"
|
||||
<<temp_node(1)<<"\t"
|
||||
<<temp_node(2)<<"\n";
|
||||
}
|
||||
vtk_mesh<<"\nCELLS\t"<<this->n_elems()<<"\t"<<this->n_elems()*5<<"\n";
|
||||
for(unsigned int i=0; i<this->n_elems(); i++) {
|
||||
Tet& temp_elem= this->get_elem(i);
|
||||
vtk_mesh<<(unsigned int)4<<"\t"
|
||||
<<temp_elem.get_node_id(0)<<"\t"
|
||||
<<temp_elem.get_node_id(1)<<"\t"
|
||||
<<temp_elem.get_node_id(2)<<"\t"
|
||||
<<temp_elem.get_node_id(3)<<"\n";
|
||||
}
|
||||
vtk_mesh<<"\nCELL_TYPES\t"<<this->n_elems()<<"\n";
|
||||
for(unsigned int i=0; i<this->n_elems(); i++) {
|
||||
vtk_mesh<<(unsigned int)10<<"\n"; // 10--tet
|
||||
}
|
||||
vtk_mesh<<"\n";
|
||||
|
||||
}
|
||||
|
||||
vtk_mesh.close();
|
||||
// done
|
||||
}
|
||||
|
||||
|
37
m3d/src/grid.h
Executable file
37
m3d/src/grid.h
Executable file
@@ -0,0 +1,37 @@
|
||||
#ifndef _GRID_H
|
||||
#define _GRID_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "node.h"
|
||||
#include "tet.h"
|
||||
|
||||
class Grid
|
||||
{
|
||||
public:
|
||||
Grid(std::string node_file, std::string tet_file);
|
||||
~Grid();
|
||||
|
||||
// tets
|
||||
unsigned int n_nodes() { return _nodes.size(); }
|
||||
unsigned int n_elems() { return _number_elems; }
|
||||
Tet& get_elem (unsigned int i);
|
||||
|
||||
void read_node();
|
||||
void read_tet ();
|
||||
|
||||
friend std::ostream& operator <<(std::ostream& os, const Grid& mesh);
|
||||
void write_out_vtk(const std::string name);
|
||||
|
||||
public:
|
||||
std::string _node_file;
|
||||
std::string _tet_file;
|
||||
std::vector<Node*> _nodes;
|
||||
std::vector<Tet*> _elements;
|
||||
unsigned int _number_elems;
|
||||
};
|
||||
|
||||
#endif // _GRID_H
|
365
m3d/src/m3d.cpp
Executable file
365
m3d/src/m3d.cpp
Executable file
@@ -0,0 +1,365 @@
|
||||
// C++ includes
|
||||
#include "m3d.h"
|
||||
#include <iostream>
|
||||
/* m3d
|
||||
* These files may be found at:
|
||||
* http://software.seg.org/2017/0006
|
||||
*
|
||||
* Please first read and accept:
|
||||
* http://software.seg.org/disclaimer.txt
|
||||
*/
|
||||
/*
|
||||
Input: a tetrahedon and an observation site
|
||||
Output: ni (outgoing normal vector of 4 surfaces)
|
||||
wi0 (heights from site to 4 surfaces
|
||||
Rij_minus and Rij_plus
|
||||
oi (projection point of site on 4 surfaces)
|
||||
Sij_minus and Sij_plus
|
||||
Rij0 (distance from site to edges of 4 surfaces)
|
||||
tij (tangential normal vector on edges)
|
||||
mij (outgoing normal vector of edges)
|
||||
*/
|
||||
M3D::M3D(Tet& tet_, Point r_):
|
||||
tet (tet_),
|
||||
r (r_),
|
||||
TOL (1e-10),
|
||||
Cm (1e-07)
|
||||
{
|
||||
// calculate variables for facets and edges
|
||||
for(int i=0; i<4; i++) {
|
||||
Point n;
|
||||
this->tet.get_facet_normal_vector(n, i);
|
||||
ni[i] = n;
|
||||
double w0;
|
||||
for(int j=0; j<3; j++) {
|
||||
Node* a[2];
|
||||
this->tet.get_facet_edge_ends (a, i, j);
|
||||
Rij_minus[i][j] = (this->r-(*a[0])).size();
|
||||
Rij_plus[i][j] = (this->r-(*a[1])).size();
|
||||
if(j==0) { w0 = (r-(*a[0]))*n;}
|
||||
}
|
||||
wi0[i]=w0;
|
||||
|
||||
Point o = r - n*w0;
|
||||
oi[i] = o;
|
||||
for(int j=0; j<3; j++) {
|
||||
Point m, t; Node* a[2];
|
||||
this->tet.get_facet_edge_normal(m, i, j);
|
||||
this->tet.get_facet_edge_tangential(t, i, j);
|
||||
this->tet.get_facet_edge_ends (a, i, j);
|
||||
Sij_minus[i][j] = ((*a[0])-o)*t;
|
||||
Sij_plus[i][j] = ((*a[1])-o)*t;
|
||||
mij0[i][j]= ((*a[0])-o)*m;
|
||||
Rij0[i][j] = std::sqrt(w0*w0+mij0[i][j]*mij0[i][j]);
|
||||
mij[i][j] = m;
|
||||
tij[i][j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Input: surface index i
|
||||
Output: k0=\iint_{T_{i}} 1/R which is given in equations (24) and (25)
|
||||
*/
|
||||
void M3D::compute_1_R(unsigned int i, double &k0)
|
||||
{
|
||||
double w0 = wi0[i];
|
||||
double temp_k=0.;
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
double part1=0, part2=0;
|
||||
if(std::abs(w0)>TOL) {
|
||||
double beta = std::atan((mij0[i][j]*Sij_plus[i][j])/(Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_plus[i][j]))
|
||||
- std::atan((mij0[i][j]*Sij_minus[i][j])/(Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_minus[i][j]));
|
||||
part2 = std::abs(w0)*beta;
|
||||
}
|
||||
double mj0 = mij0[i][j];
|
||||
if(std::abs(mj0)>TOL) {
|
||||
part1 = mj0*std::log((Rij_plus[i][j]+Sij_plus[i][j])/(Rij_minus[i][j]+Sij_minus[i][j]));
|
||||
}
|
||||
temp_k += part1 - part2;
|
||||
}
|
||||
|
||||
k0 = temp_k;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Input: surface index i
|
||||
Output: k3=\iint_{T_{i}} 1/R^3 which is given in equations (10), (17), (18) and (19)
|
||||
*/
|
||||
void M3D::compute_1_R3(unsigned int i, double &k3)
|
||||
{
|
||||
double w0 = wi0[i];
|
||||
double w0_not_zero_k3=0.;
|
||||
double w0_is_zero_k3 =0.;
|
||||
|
||||
// 1_R3!=0
|
||||
if(std::abs(w0)>TOL) {
|
||||
for(int j=0; j<3; j++) {
|
||||
double beta = std::atan((mij0[i][j]*Sij_plus[i][j])/(Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_plus[i][j]))
|
||||
- std::atan((mij0[i][j]*Sij_minus[i][j])/(Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_minus[i][j]));
|
||||
w0_not_zero_k3 += (1.0/std::abs(w0))*beta;
|
||||
}
|
||||
}
|
||||
|
||||
if(std::abs(w0)<TOL) {
|
||||
// when w0==0, site r must be outside the triangle
|
||||
// otherwise, there is a singularity in calculating 1/R3 over triangle
|
||||
for(int j=0; j<3; j++) {
|
||||
double m0 = mij0[i][j];
|
||||
if(std::abs(m0)>TOL) {
|
||||
double temp = (Sij_plus[i][j]/Rij_plus[i][j]-Sij_minus[i][j]/Rij_minus[i][j]);
|
||||
w0_is_zero_k3 += temp*(-1.0/m0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(std::abs(w0)>TOL) k3 = w0_not_zero_k3;
|
||||
else k3 = w0_is_zero_k3;
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Input: surface index i
|
||||
Output: Ki=\iint_{T_{i}} \nabla 1/ R which is given in equations (5)
|
||||
where \nabla is on the observation site r
|
||||
*/
|
||||
void M3D::compute_grad_1_R(unsigned int i, Point &Ki)
|
||||
{
|
||||
Point n = ni[i];
|
||||
double w0 = wi0[i];
|
||||
Point temp_k_minus;
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
Point part1, part2;
|
||||
if(std::abs(w0)>TOL) {
|
||||
// betaij see equation (11)
|
||||
double betaij= atan((mij0[i][j]*Sij_plus[i][j])/(Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_plus[i][j]))
|
||||
- atan((mij0[i][j]*Sij_minus[i][j])/(Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_minus[i][j]));
|
||||
part2 = n*sgn(w0)*betaij;
|
||||
}
|
||||
double Aij=0.; // see equations (20-22)
|
||||
if(std::abs(Rij0[i][j])>TOL) {
|
||||
Aij = std::log((long double)(Rij_plus[i][j]+Sij_plus[i][j])) - std::log((long double)(Rij_minus[i][j]+Sij_minus[i][j]));
|
||||
}else if(Sij_plus[i][j]>0.&&Sij_minus[i][j]>0.) {
|
||||
Aij = std::log(Sij_plus[i][j]) - std::log(Sij_minus[i][j]);
|
||||
}else if(Sij_plus[i][j]<0.&&Sij_minus[i][j]<0.) {
|
||||
Aij = std::log(Sij_minus[i][j]*-1.0)- std::log(Sij_plus[i][j]*-1.0);
|
||||
}else {
|
||||
std::cout<<"site must not on edge!\n";
|
||||
std::abort();
|
||||
}
|
||||
part1 = mij[i][j]*Aij;
|
||||
temp_k_minus = temp_k_minus + part1 + part2;
|
||||
}
|
||||
|
||||
Ki = temp_k_minus*-1.0;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Input: 4 nodes in vector T
|
||||
Output: volume(size) of tetrahedron
|
||||
*/
|
||||
double M3D::get_tri_size(std::vector<Point>& T)
|
||||
{
|
||||
assert(T.size()==3);
|
||||
Point a=T[1]+(T[0]*-1.0);
|
||||
Point b=T[2]+(T[0]*-1.0);
|
||||
Point c=a.cross(b);
|
||||
|
||||
return c.size()*0.5;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Input: surface index i
|
||||
Output: k2=\iint_{T_{i}} \nabla \nabla 1/ R which is given in equations (25)
|
||||
where \nabla is on the observation site r
|
||||
*/
|
||||
void M3D::compute_grad_grad_1_R(unsigned int i, double k2[3][3])
|
||||
{
|
||||
this->set(k2, 0.);
|
||||
double temp_k2[3][3];
|
||||
this->set(temp_k2, 0.);
|
||||
double w0 = wi0[i];
|
||||
Point n = ni[i];
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
Point grad_Aij(0,0,0); // see equations (37) and (38)
|
||||
if(std::abs(Rij0[i][j])>TOL) {
|
||||
double factor_n_mij = (Sij_plus[i][j]/(Rij0[i][j]*Rij0[i][j]*Rij_plus[i][j]) -
|
||||
Sij_minus[i][j]/(Rij0[i][j]*Rij0[i][j]*Rij_minus[i][j]))*-1.0;
|
||||
double factor_tij = (1.0/Rij_plus[i][j]-1.0/Rij_minus[i][j])*-1.0;
|
||||
grad_Aij = n*(w0*factor_n_mij) + tij[i][j]*factor_tij - mij[i][j]*(mij0[i][j]*factor_n_mij);
|
||||
}else {
|
||||
double factor_tij = (-1.0/Rij_plus[i][j]+1.0/Rij_minus[i][j]);
|
||||
grad_Aij = tij[i][j]*factor_tij;
|
||||
}
|
||||
|
||||
|
||||
Point m = mij[i][j];
|
||||
for(int l=0; l<3; l++) {
|
||||
for(int k=0; k<3; k++) {
|
||||
double temp1 = grad_Aij(l)*m(k)*-1.0;
|
||||
temp_k2[l][k] += temp1;
|
||||
}
|
||||
}
|
||||
|
||||
if(std::abs(w0)>TOL) {
|
||||
Node* a[2];
|
||||
tet.get_facet_edge_ends (a, i, j);
|
||||
Point grad_Rij_plus = (r - (*a[1]))*(1.0/Rij_plus[i][j]);
|
||||
Point grad_Rij_minus = (r - (*a[0]))*(1.0/Rij_minus[i][j]);
|
||||
Point grad_Sij_plus = tij[i][j]*-1.0;
|
||||
Point grad_Sij_minus = tij[i][j]*-1.0;
|
||||
Point grad_w0 = this->ni[i];
|
||||
Point grad_mij0 = this->mij[i][j]*-1.0;
|
||||
Point grad_Rij0 = (n*w0-mij[i][j]*mij0[i][j])*(1.0/Rij0[i][j]);
|
||||
Point grad_abs_wi0 = n*this->sgn(w0);
|
||||
double a_plus = Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_plus[i][j];
|
||||
double b_plus = mij0[i][j]*Sij_plus[i][j];
|
||||
Point grad_a_plus = grad_Rij0*(Rij0[i][j]*2.0) + grad_abs_wi0*Rij_plus[i][j]+grad_Rij_plus*std::abs(w0);
|
||||
Point grad_b_plus = grad_mij0*Sij_plus[i][j]+grad_Sij_plus*mij0[i][j];
|
||||
double a_minus = Rij0[i][j]*Rij0[i][j]+std::abs(w0)*Rij_minus[i][j];
|
||||
double b_minus = mij0[i][j]*Sij_minus[i][j];
|
||||
Point grad_a_minus = grad_Rij0*(Rij0[i][j]*2.0) + grad_abs_wi0*Rij_minus[i][j]+grad_Rij_minus*std::abs(w0);
|
||||
Point grad_b_minus = grad_mij0*Sij_minus[i][j]+grad_Sij_minus*mij0[i][j];
|
||||
Point grad_betaij_plus = (grad_b_plus*a_plus-grad_a_plus*b_plus)*(1.0/(a_plus*a_plus+b_plus*b_plus));
|
||||
Point grad_betaij_minus = (grad_b_minus*a_minus-grad_a_minus*b_minus)*(1.0/(a_minus*a_minus+b_minus*b_minus));
|
||||
|
||||
Point grad_betaij = grad_betaij_plus - grad_betaij_minus; // see equation (11)
|
||||
|
||||
for(int l=0; l<3; l++)
|
||||
for(int k=0; k<3; k++) {
|
||||
double temp2 = this->sgn(w0)*grad_betaij(l)*n(k)*-1.0;
|
||||
temp_k2[l][k] += temp2;
|
||||
}
|
||||
}
|
||||
|
||||
} // loop each facets ends
|
||||
|
||||
if(std::abs(w0)<TOL) {
|
||||
double k3 =0.;
|
||||
this->compute_1_R3(i, k3);
|
||||
for(int l=0; l<3; l++) {
|
||||
for(int k=0; k<3; k++) {
|
||||
double temp3 = k3*n(l)*n(k)*-1.0; // only need for w0=0
|
||||
temp_k2[l][k]+= temp3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy k2 = temp_k2
|
||||
for(int l=0; l<3; l++)
|
||||
for(int k=0; k<3; k++)
|
||||
k2[l][k] = temp_k2[l][k];
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a=b
|
||||
*/
|
||||
void M3D::set(double a[3][3], double b)
|
||||
{
|
||||
for(int i=0; i<3; i++)
|
||||
for(int j=0; j<3; j++) a[i][j]=b;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
sign of real number m
|
||||
*/
|
||||
double M3D::sgn(const double m)
|
||||
{
|
||||
if (std::abs(m)<TOL) return 0.;
|
||||
else return m/std::abs(m);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
calculate the magnetic potential V in equation (24)
|
||||
*/
|
||||
void M3D::V(double& v)
|
||||
{
|
||||
double temp_V=0.;
|
||||
Point M = this->tet.get_M();
|
||||
|
||||
for(int i=0; i<4; i++) {
|
||||
double k0;
|
||||
this->compute_1_R(i, k0);
|
||||
double mdotn = M*ni[i];
|
||||
temp_V+= k0*mdotn;
|
||||
}
|
||||
v = temp_V*Cm;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
calculate the magnetic field B in equation (4)
|
||||
*/
|
||||
void M3D::B(Point& b)
|
||||
{
|
||||
Point temp_B(0,0,0);
|
||||
Point M = this->tet.get_M();
|
||||
|
||||
for(int i=0; i<4; i++) {
|
||||
Point k1(0,0,0);
|
||||
this->compute_grad_1_R(i, k1);
|
||||
double mdotn = M*ni[i];
|
||||
temp_B = temp_B + k1*mdotn;
|
||||
}
|
||||
b = temp_B*(Cm*-1.0);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/*
|
||||
calculate the magnetic gradient tensor T in equation (26)
|
||||
*/
|
||||
void M3D::T(double tb[3][3])
|
||||
{
|
||||
double temp_tb[3][3];
|
||||
this->set(temp_tb, 0);
|
||||
Point M = this->tet.get_M();
|
||||
|
||||
for(int i=0; i<4; i++) {
|
||||
double k2[3][3];
|
||||
this->compute_grad_grad_1_R(i, k2);
|
||||
double mdotn = M*ni[i];
|
||||
for(int l=0; l<3; l++) {
|
||||
for(int k=0; k<3; k++) {
|
||||
temp_tb[l][k] += k2[l][k]*mdotn*Cm*-1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tb = temp_tb
|
||||
for(int i=0; i<3; i++)
|
||||
for(int j=0; j<3; j++)
|
||||
tb[i][j] = temp_tb[i][j];
|
||||
|
||||
return ;
|
||||
|
||||
|
||||
}
|
||||
|
58
m3d/src/m3d.h
Executable file
58
m3d/src/m3d.h
Executable file
@@ -0,0 +1,58 @@
|
||||
#ifndef _M3D_H
|
||||
#define _M3D_H
|
||||
|
||||
// C++ includes
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
|
||||
#include "node.h"
|
||||
#include "tet.h"
|
||||
#include "grid.h"
|
||||
|
||||
class M3D
|
||||
{
|
||||
public:
|
||||
M3D(Tet& tet, Point r);
|
||||
|
||||
void V(double& v);
|
||||
void B(Point& b);
|
||||
void T(double tb[3][3]);
|
||||
|
||||
double sgn(const double m);
|
||||
void set(double a[3][3], double b);
|
||||
void compute_1_R(unsigned int i, double &k0);
|
||||
void compute_grad_1_R(unsigned int i, Point &k1);
|
||||
void compute_grad_grad_1_R(unsigned int i, double k2[3][3]);
|
||||
void compute_1_R3(unsigned int i, double &k3);
|
||||
const double TOL;
|
||||
const double Cm ;
|
||||
double get_tri_size(std::vector<Point>& T);
|
||||
|
||||
private:
|
||||
// variables for edges
|
||||
double Rij_minus[4][3]; // equation (15)
|
||||
double Rij_plus [4][3]; // equation (14)
|
||||
double Sij_minus[4][3]; // equation (8)
|
||||
double Sij_plus [4][3]; // equation (9)
|
||||
double Rij0 [4][3]; // equation (13)
|
||||
double mij0 [4][3]; // mij0 is constant along edge eij
|
||||
Point mij [4][3]; // mij is the outgoing normal vector of edge eij
|
||||
Point tij [4][3]; // tij is the tangential normal vector of edge eij
|
||||
// variables for facets
|
||||
Point ni [4]; // ni is the outgoing normal vector of surface Ti
|
||||
double wi0 [4]; // equation (8)
|
||||
Point oi [4]; // oi is the projection point of site r on surface Ti
|
||||
// observation site and source element
|
||||
Tet& tet; // a tetrahedron
|
||||
Point r; // an observation site
|
||||
};
|
||||
|
||||
|
||||
#endif // _M3D_H
|
||||
|
||||
|
110
m3d/src/node.h
Executable file
110
m3d/src/node.h
Executable file
@@ -0,0 +1,110 @@
|
||||
#ifndef _NODE_H
|
||||
#define _NODE_H
|
||||
|
||||
// C++ includes
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include "point.h"
|
||||
|
||||
#define INVALID_UNIT
|
||||
class Node : public Point
|
||||
{
|
||||
public:
|
||||
Node (const double x=.0,
|
||||
const double y=.0,
|
||||
const double z=.0,
|
||||
const unsigned int id=0);
|
||||
Node (const Node& n);
|
||||
Node (const Point p,
|
||||
const unsigned int id =0);
|
||||
~Node ();
|
||||
|
||||
friend std::ostream& operator <<(std::ostream& os, const Node& node);
|
||||
|
||||
// Overload operators.
|
||||
Node& operator= (const Node& node);
|
||||
bool operator == (const Node& node);
|
||||
bool operator < (const Node& v) const;
|
||||
|
||||
void set_id(const unsigned int id) { _id=id; }
|
||||
unsigned int get_id() { return _id; }
|
||||
public:
|
||||
unsigned int _id;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
inline
|
||||
Node::Node (const double x, const double y,const double z,
|
||||
const unsigned int id) :
|
||||
Point (x,y,z),
|
||||
_id (id)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
Node::Node (const Node& n):
|
||||
Point (n),
|
||||
_id (n._id)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
Node::Node (const Point p,
|
||||
const unsigned int id ):
|
||||
Point(p),
|
||||
_id (id)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
Node::~Node ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
Node & Node::operator= (const Node& node)
|
||||
{
|
||||
(*this)(0) = node(0);
|
||||
(*this)(1) = node(1);
|
||||
(*this)(2) = node(2);
|
||||
_id = node._id;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
bool Node::operator== (const Node& node)
|
||||
{
|
||||
if(_id!=node._id)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
//compare the coordinates.
|
||||
return Point(*this)==Point(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
bool Node::operator < (const Node& rhs) const
|
||||
{
|
||||
// Only compare xyz location.
|
||||
return (Point)(*this)<(Point)(rhs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& operator <<(std::ostream& os, const Node& node)
|
||||
{
|
||||
os<<node._id
|
||||
<<"\t"<<node._coords[0]
|
||||
<<"\t"<<node._coords[1]
|
||||
<<"\t"<<node._coords[2];
|
||||
return os;
|
||||
}
|
||||
|
||||
#endif // NODE_H
|
218
m3d/src/point.h
Executable file
218
m3d/src/point.h
Executable file
@@ -0,0 +1,218 @@
|
||||
#ifndef _POINT_H
|
||||
#define _POINT_H
|
||||
|
||||
// C++ includes
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
Point (const double x=0., const double y=0., const double z=0.);
|
||||
Point (const Point& p);
|
||||
virtual ~Point ();
|
||||
|
||||
friend std::ostream& operator <<(std::ostream& os, const Point& point);
|
||||
|
||||
// Overload operators.
|
||||
Point& operator=(const Point& p);
|
||||
double operator () (const unsigned int i) const;
|
||||
double & operator () (const unsigned int i);
|
||||
Point operator + (const Point& v) const;
|
||||
Point operator - (const Point& v) const;
|
||||
Point operator * (const double a) const;
|
||||
double operator *(const Point& v) const;
|
||||
bool operator == (const Point& v) const;
|
||||
bool operator < (const Point& v) const;
|
||||
void operator = (const double a);
|
||||
|
||||
// Math functions
|
||||
Point cross(const Point& v) const;
|
||||
Point unit() const;
|
||||
double size() const;
|
||||
void zero();
|
||||
double* get_xyz() { return _coords; }
|
||||
|
||||
protected:
|
||||
double _coords[3];
|
||||
const double TOL ;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
inline
|
||||
Point::Point (const double x,
|
||||
const double y,
|
||||
const double z):
|
||||
TOL (1e-10)
|
||||
{
|
||||
_coords[0] = x; _coords[1] = y; _coords[2] = z;
|
||||
}
|
||||
|
||||
inline
|
||||
Point::Point (const Point &p):
|
||||
TOL (1e-10)
|
||||
{
|
||||
for (unsigned int i=0; i<3; i++)
|
||||
_coords[i] = p._coords[i];
|
||||
}
|
||||
|
||||
inline
|
||||
Point& Point::operator=(const Point& p)
|
||||
{
|
||||
_coords[0] = p._coords[0];
|
||||
_coords[1] = p._coords[1];
|
||||
_coords[2] = p._coords[2];
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
Point::~Point ()
|
||||
{
|
||||
//no space is allocated by the new operator.
|
||||
//so,there is no delete [].
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
double Point::operator ()(const unsigned int i) const
|
||||
{
|
||||
assert (i<3);
|
||||
return _coords[i];
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
double & Point::operator () (const unsigned int i)
|
||||
{
|
||||
assert (i<3);
|
||||
return _coords[i];
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
Point Point::operator + (const Point &p) const
|
||||
{
|
||||
return Point(_coords[0] + p._coords[0],
|
||||
_coords[1] + p._coords[1],
|
||||
_coords[2] + p._coords[2]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
Point Point::operator - (const Point& p) const
|
||||
{
|
||||
return Point(_coords[0] - p._coords[0],
|
||||
_coords[1] - p._coords[1],
|
||||
_coords[2] - p._coords[2]);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
Point Point::operator * (const double factor) const
|
||||
{
|
||||
return Point(_coords[0]*factor, _coords[1]*factor,_coords[2]*factor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
double Point::operator * (const Point&p) const
|
||||
{
|
||||
return (_coords[0]*p(0) + _coords[1]*p(1) + _coords[2]*p(2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
bool Point::operator == (const Point& rhs) const
|
||||
{
|
||||
return ((fabs(_coords[0] - rhs._coords[0]) +
|
||||
fabs(_coords[1] - rhs._coords[1]) +
|
||||
fabs(_coords[2] - rhs._coords[2])) < 3*TOL);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
bool Point::operator < (const Point& rhs) const
|
||||
{
|
||||
//First we assume (this)<rhs true
|
||||
if (*this == rhs) return false;
|
||||
if ((*this)(0) < rhs(0)) return true; // <
|
||||
else if ((*this)(0) > rhs(0)) return false;// >
|
||||
else if (std::abs((*this)(0)-rhs(0))<1e-6){//vx=rhsx
|
||||
if ((*this)(1) < rhs(1)) return true;
|
||||
else if ((*this)(1) > rhs(1)) return false;
|
||||
else if (std::abs((*this)(1)-rhs(1))<1e-6){//vy=rhsy
|
||||
if ((*this)(2) < rhs(2)) return true;
|
||||
else if ((*this)(2) > rhs(2)) return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void Point::operator = (const double a)
|
||||
{
|
||||
_coords[0] = a; _coords[1] = a; _coords[2] = a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
Point Point::cross(const Point& p) const
|
||||
{
|
||||
return Point(_coords[1]*p._coords[2] - _coords[2]*p._coords[1],
|
||||
-_coords[0]*p._coords[2] + _coords[2]*p._coords[0],
|
||||
_coords[0]*p._coords[1] - _coords[1]*p._coords[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
Point Point::unit() const
|
||||
{
|
||||
const double length = size();
|
||||
return Point(_coords[0]/length,
|
||||
_coords[1]/length,
|
||||
_coords[2]/length);
|
||||
}
|
||||
|
||||
inline
|
||||
double Point::size() const
|
||||
{
|
||||
double value= std::pow(_coords[0],2)+
|
||||
std::pow(_coords[1],2)+
|
||||
std::pow(_coords[2],2);
|
||||
|
||||
return std::sqrt(value);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void Point::zero()
|
||||
{
|
||||
_coords[0]=0.;
|
||||
_coords[1]=0.;
|
||||
_coords[2]=0.;
|
||||
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& operator <<(std::ostream& os, const Point& point)
|
||||
{
|
||||
os<<point(0)<<"\t"<<point(1)<<"\t"<<point(2);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
#endif // _POINT_H
|
239
m3d/src/tet.h
Executable file
239
m3d/src/tet.h
Executable file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
0
|
||||
TET
|
||||
/|\
|
||||
0 / | \
|
||||
/ | \2
|
||||
/ 1| \
|
||||
1 ..4.|....3
|
||||
\ | /
|
||||
\ | /
|
||||
3 \ | /5
|
||||
\|/
|
||||
|
||||
2
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _TET_H
|
||||
#define _TET_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include "node.h"
|
||||
|
||||
class Tet
|
||||
{
|
||||
public:
|
||||
Tet (unsigned int id, Node* v[4], Point M);
|
||||
unsigned int get_id () { return _id;}
|
||||
Point get_M() { return _M;}
|
||||
unsigned int get_node_id(unsigned int i);
|
||||
void get_nodes(Node* nodes[4]);
|
||||
void get_facet(Node* facet[3], unsigned int i);
|
||||
void get_facet_normal_vector(Point& n,unsigned int i);
|
||||
void get_facet_edge_nodes(Node* v[2], unsigned int i, unsigned int j);
|
||||
void get_facet_edge_normal(Point& m, unsigned int i, unsigned int j);
|
||||
void get_facet_edge_tangential(Point& t, unsigned int i, unsigned int j);
|
||||
void get_facet_edge_ends (Node* a[2], unsigned int i, unsigned int j);
|
||||
double get_size();
|
||||
private:
|
||||
unsigned int _id;
|
||||
Node* _v[4];
|
||||
Point _M;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
Tet::Tet(unsigned int id,
|
||||
Node* v[4],
|
||||
Point M)
|
||||
{
|
||||
this->_id = id;
|
||||
for(unsigned int i=0; i<4; i++) this->_v[i]=v[i];
|
||||
this->_M = M;
|
||||
|
||||
}
|
||||
|
||||
inline double Tet::get_size()
|
||||
{
|
||||
const Point & a=(*_v[1])+((*_v[0])*-1.0);
|
||||
const Point & b=(*_v[1])+((*_v[2])*-1.0);
|
||||
const Point & c=(*_v[1])+((*_v[3])*-1.0);
|
||||
return std::abs( a*(c.cross(b)) )/6.;
|
||||
}
|
||||
|
||||
inline
|
||||
unsigned int Tet::get_node_id(unsigned int i)
|
||||
{
|
||||
assert(i<4);
|
||||
return this->_v[i]->get_id();
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void Tet::get_nodes(Node* nodes[4])
|
||||
{
|
||||
for(int i=0; i<4; i++) nodes[i] = this->_v[i];
|
||||
return;
|
||||
}
|
||||
|
||||
inline
|
||||
void Tet::get_facet(Node* facet[3], unsigned int i)
|
||||
{
|
||||
assert(i<4);
|
||||
switch(i) {
|
||||
case 0:
|
||||
facet[0] = _v[1]; facet[1] = _v[2]; facet[2] = _v[3];
|
||||
break;
|
||||
case 1:
|
||||
facet[0] = _v[0]; facet[1] = _v[2]; facet[2] = _v[3];
|
||||
break;
|
||||
case 2:
|
||||
facet[0] = _v[0]; facet[1] = _v[1]; facet[2] = _v[3];
|
||||
break;
|
||||
case 3:
|
||||
facet[0] = _v[0]; facet[1] = _v[1]; facet[2] = _v[2];
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void Tet::get_facet_normal_vector(Point& n,unsigned int i)
|
||||
{
|
||||
Point normal, facet_center;
|
||||
assert(i<4);
|
||||
switch(i) {
|
||||
case 0:
|
||||
normal = ((*_v[3])-(*_v[2])).cross((*_v[1])-(*_v[2])).unit();
|
||||
facet_center = ((*_v[1])+(*_v[2])+(*_v[3]))*(1.0/3.0);
|
||||
break;
|
||||
case 1:
|
||||
normal = ((*_v[0])-(*_v[3])).cross((*_v[2])-(*_v[3])).unit();
|
||||
facet_center = ((*_v[0])+(*_v[2])+(*_v[3]))*(1.0/3.0);
|
||||
break;
|
||||
case 2:
|
||||
normal = ((*_v[3])-(*_v[0])).cross((*_v[1])-(*_v[0])).unit();
|
||||
facet_center = ((*_v[0])+(*_v[1])+(*_v[3]))*(1.0/3.0);
|
||||
break;
|
||||
case 3:
|
||||
normal = ((*_v[2])-(*_v[1])).cross((*_v[0])-(*_v[1])).unit();
|
||||
facet_center = ((*_v[0])+(*_v[1])+(*_v[2]))*(1.0/3.0);
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
|
||||
Point center = ((*_v[0])+(*_v[1])+(*_v[2])+(*_v[3]))*(0.25);
|
||||
// we need outgoing normal vector
|
||||
if(normal*(facet_center-center)<0.0) normal= normal*-1.0;
|
||||
|
||||
n = normal;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* 1
|
||||
0---------2
|
||||
\ /
|
||||
\ /
|
||||
2 \ / 0
|
||||
\/
|
||||
1
|
||||
*/
|
||||
inline
|
||||
void Tet::get_facet_edge_nodes(Node* v[2], unsigned int i, unsigned int j)
|
||||
{
|
||||
assert(i<4);
|
||||
assert(j<3);
|
||||
Node* facet[3];
|
||||
this->get_facet(facet, i);
|
||||
switch(j) {
|
||||
case 0:
|
||||
v[0] = facet[1]; v[1] = facet[2];
|
||||
break;
|
||||
case 1:
|
||||
v[0] = facet[2]; v[1] = facet[0];
|
||||
break;
|
||||
case 2:
|
||||
v[0] = facet[0]; v[1] = facet[1];
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void Tet::get_facet_edge_normal(Point& m, unsigned int i, unsigned int j)
|
||||
{
|
||||
assert(i<4);
|
||||
assert(j<3);
|
||||
Node* v[2];
|
||||
this->get_facet_edge_nodes(v, i, j);
|
||||
Point t = ((*v[1])-(*v[0])).unit();
|
||||
Point n;
|
||||
this->get_facet_normal_vector(n, i);
|
||||
Point temp_m = t.cross(n);
|
||||
// we need outgoing normal on edge
|
||||
Node* facet[3];
|
||||
this->get_facet(facet, i);
|
||||
Point facet_center = ((*facet[0])+(*facet[1])+(*facet[2]))*(1.0/3.0);
|
||||
Point edge_center = ((*v[1])+(*v[0]))*0.5;
|
||||
if(temp_m*(edge_center-facet_center)<0.0) temp_m= temp_m*-1.0;
|
||||
|
||||
m = temp_m;
|
||||
return;
|
||||
}
|
||||
|
||||
inline
|
||||
void Tet::get_facet_edge_tangential(Point& t, unsigned int i, unsigned int j)
|
||||
{
|
||||
assert(i<4);
|
||||
assert(j<3);
|
||||
Point m;
|
||||
this->get_facet_edge_normal(m, i, j);
|
||||
Point n;
|
||||
this->get_facet_normal_vector(n, i);
|
||||
t = n.cross(m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
a[0]-----------a[1]
|
||||
(a-) (a+)
|
||||
*/
|
||||
inline
|
||||
void Tet::get_facet_edge_ends (Node* a[2], unsigned int i, unsigned int j)
|
||||
{
|
||||
assert(i<4);
|
||||
assert(j<3);
|
||||
Point t;
|
||||
this->get_facet_edge_tangential(t, i, j);
|
||||
Node* v[2];
|
||||
this->get_facet_edge_nodes(v, i, j);
|
||||
|
||||
Point temp_t = ((*v[1])-(*v[0])).unit();
|
||||
if(t*temp_t>0.0) {
|
||||
a[0] = v[0];
|
||||
a[1] = v[1];
|
||||
}else if(t*temp_t<0.) {
|
||||
a[0] = v[1];
|
||||
a[1] = v[0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // _Tet_h
|
||||
|
||||
|
Reference in New Issue
Block a user