void testDecomposition(MaterialGenerator generator)
{
    for (int count = 0; count < ITERATIONS; count++) {
        CalcNode anisotropicNode;
        AnisotropicMatrixImplementation matrix;

        string testMaterialName = "AnisotropicMatrix3D_FuzzyMultiplication_" + to_string(count);
        NumericalAnisotropicElasticMaterial mat = generator(testMaterialName);
        anisotropicNode.setMaterialId(Engine::getInstance().addMaterial(&mat));

        for (int i = 0; i < 3; i++) {
            switch (i) {
            case 0: matrix.createAx(anisotropicNode);
                break;
            case 1: matrix.createAy(anisotropicNode);
                break;
            case 2: matrix.createAz(anisotropicNode);
                break;
            }

            // Test decomposition
            ASSERT_TRUE( matrix.getU1() * matrix.getL() * matrix.getU() |= matrix.getA() );
            // Test eigenvalues and eigenvectors
            ASSERT_TRUE( matrix.getU1() * matrix.getL() |= matrix.getA() * matrix.getU1() );

        }
        Engine::getInstance().clear();
    }
};
Exemple #2
0
/**
 * Launch this dialog in order to edit the format of the specified database.
 *
 * @param subject The database whose format is to be edited
 */
int DBEditor::edit(Database *subject)
{
    db = subject;
    columnEditor = new ColumnEditor(db, this);
    originalCols = db->listColumns();
    renamedCols = db->listColumns();
    int count = originalCols.count();
    for (int i = 0; i < count; i++) {
        QString name = originalCols[i];
        int type = db->getType(name);
        QString defaultVal = db->getDefault(name);
        if (type == CALC) {
            int decimals = 2;
            CalcNode *root = db->loadCalc(name, &decimals);
            calcMap.insert(name, root);
            decimalsMap.insert(name, decimals);
            if (root != 0) {
                defaultVal = root->equation(db);
            }
        }
        info.Add(ceName [name.toUtf8()] + ceType [type]
                 + ceDefault [defaultVal.toUtf8()]
                 + ceOldIndex [i] + ceNewIndex [i]);
    }
    updateTable();
    return exec();
}
void RectangularCutCubicMeshGenerator::loadMesh(RectangularCutCubicMesh* mesh, 
	GCMDispatcher* dispatcher, float h, int numX, int numY, int numZ,
	                                    int minX, int minY, int minZ,
	                                    int maxX, int maxY, int maxZ)
{
	mesh->setNumX(numX);
	mesh->setNumY(numY);
	mesh->setNumZ(numZ);

	static int startNumber = 0;
    for( int k = 0; k <= numZ; k++ )
        for( int j = 0; j <= numY; j++ )
            for( int i = 0; i <= numX; i++ )
            {
				int n = i*(numY+1)*(numZ+1) + j*(numZ+1) + k + startNumber;
                float x = i*h;
                float y = j*h;
                float z = k*h;
                CalcNode* node = new CalcNode();//(n, x, y, z);
                node->number = n;
                node->coords[0] = x;
                node->coords[1] = y;
                node->coords[2] = z;
                node->setPlacement(true);
                mesh->addNode( *node );
            }
	mesh->setCutArea( AABB(minX*h, maxX*h, minY*h, maxY*h, minZ*h, maxZ*h) );
    mesh->preProcess();
	startNumber += 100000000;
}
void MshTetrFileReader::readFile(string file, TetrMeshFirstOrder* mesh, GCMDispatcher* dispatcher, int rank, bool ignoreDispatcher)
{
    assert_true(mesh);
    assert_true(dispatcher);
    int tetrsCount = 0;
    int fileVer;
    string str;
    int tmp_int;
    float tmp_float;
    int number_of_nodes;
    int number_of_elements;

    ifstream infile;
    infile.open(file.c_str(), ifstream::in);
    if(!infile.is_open())
        THROW_INVALID_INPUT( "Can not open msh file" );

    LOG_DEBUG("Reading msh file...");

    infile >> str;
    if(strcmp(str.c_str(),"$MeshFormat") != 0)
        THROW_INVALID_INPUT("Wrong file format");

    infile >> tmp_float >> tmp_int >> tmp_int;
    fileVer = (int)(tmp_float*10);

    infile >> str;
    if(strcmp(str.c_str(),"$EndMeshFormat") != 0)
        THROW_INVALID_INPUT("Wrong file format");

    LOG_DEBUG("Header Ok");

    infile >> str;
    if(strcmp(str.c_str(),"$Nodes") != 0)
        THROW_INVALID_INPUT("Wrong file format");

    infile >> number_of_nodes;
    LOG_DEBUG("File contains " << number_of_nodes << " nodes");
    vector<CalcNode*>* nodes = new vector<CalcNode*>;

    for(int i = 0; i < number_of_nodes; i++)
    {
        infile >> tmp_int;
        if( tmp_int > 0 )
        {
            float coords[3];
            infile >> coords[0] >> coords[1] >> coords[2];
            if( ignoreDispatcher || dispatcher->isMine( coords, mesh->getBody()->getId() ) )
            {
                CalcNode* node = new CalcNode();
                node->number = tmp_int - 1;
                node->coords[0] = coords[0];
                node->coords[1] = coords[1];
                node->coords[2] = coords[2];
                node->setPlacement(true);
                nodes->push_back( node );
            }
        }
        else
        {
TEST(AnisotropicMatrix3D, AnalyticalEqNumerical)
{
    srand(time(NULL));
    for (int count = 0; count < ITERATIONS; count++) {
        AnisotropicMatrix3DAnalytical analyticalMatrix;
        AnisotropicMatrix3D numericalMatrix;
        CalcNode anisotropicNode;

        string testMaterialName = "AnisotropicMatrix3D_AnalyticalEqNumerical";
        auto mat = generateRandomMaterial(testMaterialName);
        anisotropicNode.setMaterialId(Engine::getInstance().addMaterial(&mat));

        analyticalMatrix.createAx(anisotropicNode);
        numericalMatrix.createAx(anisotropicNode);
        ASSERT_TRUE( analyticalMatrix.getA() |= numericalMatrix.getA() );

        analyticalMatrix.createAy(anisotropicNode);
        numericalMatrix.createAy(anisotropicNode);
        ASSERT_TRUE( analyticalMatrix.getA() |= numericalMatrix.getA() );

        analyticalMatrix.createAz(anisotropicNode);
        numericalMatrix.createAz(anisotropicNode);
        ASSERT_TRUE( analyticalMatrix.getA() |= numericalMatrix.getA() );

        Engine::getInstance().clear();
    }
};
Exemple #6
0
/**
 * Update any defined calculations to reflect the deletion of a column.
 *
 * @param name The name of the column that was deleted
 */
void DBEditor::deleteColumnRefs(const QString &name)
{
    NameCalcMap::Iterator iter;
    QStringList deletions;
    for (iter = calcMap.begin(); iter != calcMap.end(); ++iter) {
        QString calcName = iter.key();
        CalcNode *calcRoot = iter.value();
        if (calcRoot != 0) {
            int index = info.Find(ceName [calcName.toUtf8()]);
            if (calcRoot->deleteColumn(name)) {
                delete calcRoot;
                deletions.append(calcName);
                ceDefault (info[index]) = "";
            }
            else {
                ceDefault (info[index]) = calcRoot->equation().toUtf8();
            }
        }
    }
    int count = deletions.count();
    for (int i = 0; i < count; i++) {
        calcMap.remove(deletions[i]);
        calcMap.insert(deletions[i], 0);
    }
}
void compareDecomposition(MaterialGenerator generator)
{
    for (int count = 0; count < ITERATIONS; count++) {
        CalcNode anisotropicNode;
        AnisotropicMatrixImplementation1 matrix1;
        AnisotropicMatrixImplementation2 matrix2;

        string testMaterialName = "AnisotropicMatrix3D_Comparing_" + to_string(count);
        NumericalAnisotropicElasticMaterial mat = generator(testMaterialName);
        anisotropicNode.setMaterialId(Engine::getInstance().addMaterial(&mat));

        for (int i = 0; i < 3; i++) {
            switch (i) {
            case 0: matrix1.createAx(anisotropicNode);
                matrix2.createAx(anisotropicNode);
                break;
            case 1: matrix1.createAy(anisotropicNode);
                matrix2.createAy(anisotropicNode);
                break;
            case 2: matrix1.createAz(anisotropicNode);
                matrix2.createAz(anisotropicNode);
                break;
            }

            int j_an, j_num, k;
            float eigenvA, ratio;

            // Through all eigenvalues
            for(j_an = 0; j_an < 6; j_an++) {
                eigenvA = matrix1.getL().get(j_an, j_an);

                // Finding the same eigenvalue in numericalMatrix
                j_num = 0;
                while(fabs(eigenvA - matrix2.getL().get(j_num, j_num)) > fmax(fabs(eigenvA), fabs(matrix2.getL().get(j_num, j_num)))*10.0*EQUALITY_TOLERANCE) { 
					j_num++; 
					//if(j_num > 5) THROW_INVALID_ARG("Remaining quality is inaccessible!");
				}

                // Finding the first exapmle ratio of components
                k = -1;
                do {
                    k++;
                    ratio = matrix1.getU1().get(k, j_an)/matrix2.getU1().get(k, j_num);
                } while(fabs(matrix2.getU1().get(k, j_num)) < 1.0e-8);

                // Comparing this ratio with another ratios
                for(k = 0; k < 9; k++) {
                    if(fabs(matrix1.getU1().get(k, j_an)) < 1.0e-8) ASSERT_NEAR(matrix2.getU1().get(k, j_num), 0.0, 1.0e-8);
                    else ASSERT_NEAR(ratio, matrix1.getU1().get(k, j_an)/matrix2.getU1().get(k, j_num), fmax(fabs(ratio), fabs(matrix1.getU1().get(k, j_an)/matrix2.getU1().get(k, j_num)))*100.0*EQUALITY_TOLERANCE);
                }
            }
        }
        Engine::getInstance().clear();
    }
};
Exemple #8
0
/**
 * Update any defined calculations to reflect a column renaming.
 *
 * @param oldName The old column name
 * @param newName The new column name
 */
void DBEditor::renameColumnRefs(const QString &oldName, const QString &newName)
{
    NameCalcMap::Iterator iter;
    for (iter = calcMap.begin(); iter != calcMap.end(); ++iter) {
        QString calcName = iter.key();
        CalcNode *calcRoot = iter.value();
        if (calcRoot != 0) {
            int index = info.Find(ceName [calcName.toUtf8()]);
            calcRoot->renameColumn(oldName, newName);
            ceDefault (info[index]) = calcRoot->equation().toUtf8();
        }
    }
}
void RectangularCutCubicMesh::findBorderNodeNormal(const CalcNode& node, 
	float* x, float* y, float* z, bool debug)
{
    //CalcNode& node = getNode( border_node_index );
    assert_true(node.isBorder() );
    float normal[3];
    normal[0] = normal[1] = normal[2] = 0.0;
	uint i = node.contactDirection;
    for( int cntr = 0; cntr < 3; cntr++) {
        if( fabs(node.coords[i] - outline.min_coords[i]) < EQUALITY_TOLERANCE ) {
            normal[i] = -1;
            break;
        }
        if( fabs(node.coords[i] - outline.max_coords[i]) < EQUALITY_TOLERANCE ) {
            normal[i] = 1;
            break;
        }
		if(cutArea.isInAABB(node)) {
			if( fabs(node.coords[i] - cutArea.min_coords[i]) < EQUALITY_TOLERANCE ) {
				normal[i] = 1;
				break;
			}
			if( fabs(node.coords[i] - cutArea.max_coords[i]) < EQUALITY_TOLERANCE ) {
				normal[i] = -1;
				break;
			}
		}
		i = (i + 1) % 3;
    }
    *x = normal[0];
    *y = normal[1];
    *z = normal[2];
};
int InterpolationFixedAxis::prepare_node(CalcNode& cur_node, RheologyMatrixPtr rheologyMatrix,
                                              float time_step, int stage, Mesh* mesh,
                                              float* dksi, bool* inner, vector<CalcNode>& previous_nodes,
                                              float* outer_normal, bool debug)
{
    assert_ge(stage, 0);
    assert_le(stage, 2);

    if (cur_node.isBorder())
        mesh->findBorderNodeNormal(cur_node, &outer_normal[0], &outer_normal[1], &outer_normal[2], false);

    LOG_TRACE("Preparing elastic matrix");
    //  Prepare matrixes  A, Lambda, Omega, Omega^(-1)

    switch (stage) {
    case 0: rheologyMatrix->decomposeX(cur_node);
        break;
    case 1: rheologyMatrix->decomposeY(cur_node);
        break;
    case 2: rheologyMatrix->decomposeZ(cur_node);
        break;
    }
    LOG_TRACE("Preparing elastic matrix done");

    LOG_TRACE("Elastic matrix eigen values:\n" << rheologyMatrix->getL());

    for (int i = 0; i < 9; i++)
        dksi[i] = -rheologyMatrix->getL(i, i) * time_step;

    return find_nodes_on_previous_time_layer(cur_node, stage, mesh, dksi, inner, previous_nodes, outer_normal, debug);
}
Exemple #11
0
bool BasicCubicMesh::interpolateBorderNode_old(real x, real y, real z,
                                real dx, real dy, real dz, CalcNode& node)
{
    //int meshSizeX = 1 + (outline.maxX - outline.minX + meshH * 0.1) / meshH;
    float coords[3];
    float tx = coords[0] = x + dx;
    float ty = coords[1] = y + dy;
    float tz = coords[2] = z + dz;

    if( outline.isInAABB(tx, ty, tz) != outline.isInAABB(x, y, z) )
    {
        // FIXME_ASAP
        float minH = std::numeric_limits<float>::infinity();
        int num = -1;
        for(int i = 1; i < getNodesNumber(); i++) {
            CalcNode& node = getNodeByLocalIndex(i);
			if(node.isBorder()) {
				float h = distance(coords, node.coords);
				if( h < minH ) {
					minH = h;
					num = i;
				}
			}
        }
        node = getNodeByLocalIndex(num);
        
        return true;
    }
	
    return false;
};
void TetrMeshSecondOrder::fillSecondOrderNode(CalcNode& newNode, int nodeIdx1, int nodeIdx2)
{
    CalcNode& node1 = getNode(nodeIdx1);
    CalcNode& node2 = getNode(nodeIdx2);

    for (int i = 0; i < 3; i++)
        newNode.coords[i] = (node1.coords[i] + node2.coords[i]) * 0.5;

    for (int i = 0; i < 9; i++)
        newNode.values[i] = (node1.values[i] + node2.values[i]) * 0.5;

    newNode.setRho((node1.getRho() + node2.getRho()) * 0.5);
    newNode.setMaterialId(node1.getMaterialId());

    newNode.setPlacement(true);
    newNode.setOrder(2);
}
Exemple #13
0
void launcher::setIsotropicElasticPWave(CalcNode& node, const Vector3& direction, real amplitudeScale, bool compression)
{
    assert_gt(amplitudeScale, 0.0);

    const MaterialPtr& mat = node.getMaterial();

    auto la = mat->getLa();
    auto  mu = mat->getMu();
    auto  rho = mat->getRho();

    auto pWaveVelocity = sqrt(la + 2 * mu / rho);

    auto dir = vectorNormalize(direction);

    auto sxx = la*amplitudeScale;
    auto szz = sxx;
    auto syy = (la + 2*mu)*amplitudeScale;

    if (!compression)
    {
        sxx = -sxx;
        syy = -syy;
        szz = -szz;
    }

    StressTensor tensor({
        sxx, 0.0, 0.0,
             syy, 0.0,
                  szz
    });

    auto alpha = atan2(dir.y, dir.x) - M_PI/2;
    
    auto _dir = getZRotationMatrix(alpha)*dir;

    auto beta = atan2(_dir.z, _dir.y);

    auto s = getZRotationMatrix(-alpha) *getXRotationMatrix(-beta);

    tensor.transform(s);

    node.sxx = tensor.xx;
    node.sxy = tensor.xy;
    node.sxz = tensor.xz;
    node.syy = tensor.yy;
    node.syz = tensor.yz;
    node.szz = tensor.zz;

    auto velocity = (compression ? -1 : 1) * vectorNormalize(dir)*pWaveVelocity*amplitudeScale;

    node.vx = velocity.x;
    node.vy = velocity.y;
    node.vz = velocity.z;
}
void gcm::LineFirstOrderInterpolator::interpolate(CalcNode& node, CalcNode& node0, CalcNode& node1)
{
    LOG_TRACE("Start interpolation");

    float lenTotal = distance(node0.coords, node1.coords);

    float factor0 = distance(node.coords, node1.coords) / lenTotal;

    float factor1 = distance(node.coords, node0.coords) / lenTotal;

    // If we see potential instability
    if (factor0 + factor1 > 1.0) {
        // If it is small - treat instability as minor and just 'smooth' it
        if (factor0 + factor1 < 1 + EQUALITY_TOLERANCE) // FIXME@avasyukov
        {
            float sum = factor0 + factor1;
            factor0 = factor0 / sum;
            factor1 = factor1 / sum;
        }
            // Throw exception
        else {
            LOG_ERROR("Requested node: " << node);
            LOG_ERROR("Node #1: " << node0);
            LOG_ERROR("Node #2: " << node1);
            LOG_ERROR("Factor: " << factor0 + factor1);
            THROW_BAD_MESH("Sum of factors is greater than 1.0");
        }
    }

    for (int i = 0; i < 9; i++) {
        node.values[i] = (node0.values[i] * factor0 + node1.values[i] * factor1);
    }

    node.setRho(node0.getRho() * factor0 + node1.getRho() * factor1);
    node.setMaterialId(node0.getMaterialId());

    LOG_TRACE("Interpolation done");
}
void testIsotropicTransition()
{
    for (int count = 0; count < ITERATIONS; count++) {
        gcm_real la = ISOTROPIC_LAMBDA_LIMIT * (double) rand() / RAND_MAX;
        gcm_real mu = ISOTROPIC_MU_LIMIT * (double) rand() / RAND_MAX;
        gcm_real rho = ISOTROPIC_RHO_LIMIT * (double) rand() / RAND_MAX;
        gcm_real crackThreshold = numeric_limits<gcm_real>::infinity();

        CalcNode isotropicNode;
        CalcNode anisotropicNode;

        IAnisotropicElasticMaterial::RheologyParameters params;
        params.c11 = params.c22 = params.c33 = la + 2 * mu;
        params.c44 = params.c55 = params.c66 = mu;
        params.c12 = params.c13 = params.c23 = la;
        params.c14 = params.c15 = params.c16 = 0.0;
        params.c24 = params.c25 = params.c26 = 0.0;
        params.c34 = params.c35 = params.c36 = 0.0;
        params.c45 = params.c46 = params.c56 = 0.0;

        IsotropicElasticMaterial m1("AnisotropicMatrix3D_IsotropicTransition_IEM", rho, crackThreshold, la, mu);
        MaterialImplementation m2("AnisotropicMatrix3D_IsotropicTransition_AEM", rho, crackThreshold, params);

        isotropicNode.setMaterialId(Engine::getInstance().addMaterial(&m1));
        anisotropicNode.setMaterialId(Engine::getInstance().addMaterial(&m2));

        RheologyMatrix3D& isotropicMatrix = isotropicNode.getRheologyMatrix();
        RheologyMatrix3D& anisotropicMatrix = anisotropicNode.getRheologyMatrix();

        for (int i = 0; i < 3; i++) {
            switch (i) {
            case 0: isotropicMatrix.createAx(isotropicNode);
                anisotropicMatrix.createAx(anisotropicNode);
                break;
            case 1: isotropicMatrix.createAy(isotropicNode);
                anisotropicMatrix.createAy(anisotropicNode);
                break;
            case 2: isotropicMatrix.createAz(isotropicNode);
                anisotropicMatrix.createAz(anisotropicNode);
                break;
            }

            for (int j = 0; j < 9; j++)
                for (int k = 0; k < 9; k++)
                    ASSERT_NEAR(anisotropicMatrix.getA(j, k), isotropicMatrix.getA(j, k), EQUALITY_TOLERANCE);
        }
        Engine::getInstance().clear();
    }
};
Exemple #16
0
void BasicCubicMesh::findBorderNodeNormal(const CalcNode& node, float* x, float* y, float* z, bool debug)
{
    assert_true(node.isBorder() );
	
    float normal[3];
    normal[0] = normal[1] = normal[2] = 0.0;

	uint i = node.contactDirection;
	for( int cntr = 0; cntr < 3; cntr ++) {
        if( fabs(node.coords[i] - outline.min_coords[i]) < EQUALITY_TOLERANCE ) {
            normal[i] = -1;
            break;
        }
        if( fabs(node.coords[i] - outline.max_coords[i]) < EQUALITY_TOLERANCE ) {
            normal[i] = 1;
            break;
        }
		i = (i + 1) % 3;
    }
    *x = normal[0];
    *y = normal[1];
    *z = normal[2];
};
uchar RheologyModel::getSizeOfValuesInODE() const {
    CalcNode tmpNode = newNode(nodeType);
    return tmpNode.getSizeOfValuesInODE();
}
void SlidingContactCalculator::doCalc(CalcNode& cur_node, CalcNode& new_node, CalcNode& virt_node,
                            RheologyMatrixPtr matrix, vector<CalcNode>& previousNodes, bool inner[],
                            RheologyMatrixPtr virt_matrix, vector<CalcNode>& virtPreviousNodes, bool virt_inner[],
                            float outer_normal[], float scale)
{
    assert_eq(previousNodes.size(), 9);
    assert_eq(virtPreviousNodes.size(), 9);

    if (isFreeBorder(cur_node, virt_node, outer_normal))
    {
        fbc->doCalc(cur_node, new_node, matrix, previousNodes, inner, outer_normal, scale);
        return;
    }

    // Here we will store (omega = Matrix_OMEGA * u)
    float omega[9];
    float virt_omega[9];

    int posInEq18 = 0;
    int curNN = 0;

    // For all omegas of real node
    for(int i = 0; i < 9; i++)
    {
        LOG_TRACE("PrNode: " << previousNodes[i]);
        // If omega is 'inner'
        if(inner[i])
        {
            LOG_TRACE("INNER");
            // omega on new time layer is equal to omega on previous time layer along characteristic
            omega[i] = 0;
            for( int j = 0; j < 9; j++ ) {
                omega[i] += matrix->getU(i,j) * previousNodes[i].values[j];
            }

            // then we must set the corresponding values of the 18x18 matrix
            gsl_vector_set( om_gsl, 6 * curNN + posInEq18, omega[i] );

            for( int j = 0; j < 9; j++ ) {
                gsl_matrix_set( U_gsl, 6 * curNN + posInEq18, j, matrix->getU( i, j ) );
            }
            for( int j = 9; j < 18; j++ ) {
                gsl_matrix_set( U_gsl, 6 * curNN + posInEq18, j, 0 );
            }
            posInEq18++;
        }
    }

    posInEq18 = 0;
    curNN = 1;
    // For all omegas of virtual node
    for(int i = 0; i < 9; i++)
    {
        LOG_TRACE("VirtPrNode: " << virtPreviousNodes[i]);
        // If omega is 'inner'
        if(virt_inner[i])
        {
            LOG_TRACE("INNER");
            // omega on new time layer is equal to omega on previous time layer along characteristic
            virt_omega[i] = 0;
            for( int j = 0; j < 9; j++ ) {
                virt_omega[i] += virt_matrix->getU(i,j) * virtPreviousNodes[i].values[j];
            }

            // then we must set the corresponding values of the 18x18 matrix
            gsl_vector_set( om_gsl, 6 * curNN + posInEq18, virt_omega[i] );

            for( int j = 0; j < 9; j++ ) {
                gsl_matrix_set( U_gsl, 6 * curNN + posInEq18, j, 0 );
            }
            for( int j = 9; j < 18; j++ ) {
                gsl_matrix_set( U_gsl, 6 * curNN + posInEq18, j, virt_matrix->getU( i, j - 9 ) );
            }
            posInEq18++;
        }
    }

    // Clear the rest 6 rows of the matrix
    for( int strN = 12; strN < 18; strN++ ) {
        for( int colN = 0; colN < 18; colN++ ) {
            gsl_matrix_set( U_gsl, strN, colN, 0 );
        }
    }

    for( int strN = 12; strN < 18; strN++ ) {
        gsl_vector_set( om_gsl, strN, 0 );
	}
	
	float local_n[3][3];
	local_n[0][0] = outer_normal[0];
	local_n[0][1] = outer_normal[1];
	local_n[0][2] = outer_normal[2];
	createLocalBasis(local_n[0], local_n[1], local_n[2]);
	
    // Normal velocities are equal
    gsl_matrix_set( U_gsl, 12, 0, local_n[0][0]);
    gsl_matrix_set( U_gsl, 12, 1, local_n[0][1]);
    gsl_matrix_set( U_gsl, 12, 2, local_n[0][2]);
    gsl_matrix_set( U_gsl, 12, 9,  - local_n[0][0]);
    gsl_matrix_set( U_gsl, 12, 10, - local_n[0][1]);
    gsl_matrix_set( U_gsl, 12, 11, - local_n[0][2]);

    // We use outer normal to find total stress vector (sigma * n) - sum of normal and shear - and tell it is equal
    // TODO - is it ok?
    // TODO - never-ending questions - is everything ok with (x-y-z) and (ksi-eta-dzeta) basises?

    // TODO FIXME - it works now because exactly the first axis is the only one where contact is possible
    // and it coincides with outer normal

    // Normal stresses are equal
    gsl_matrix_set(U_gsl, 13, 3, local_n[0][0] * local_n[0][0]);
    gsl_matrix_set(U_gsl, 13, 4, 2 * local_n[0][1] * local_n[0][0]);
    gsl_matrix_set(U_gsl, 13, 5, 2 * local_n[0][2] * local_n[0][0]);
    gsl_matrix_set(U_gsl, 13, 6, local_n[0][1] * local_n[0][1]);
    gsl_matrix_set(U_gsl, 13, 7, 2 * local_n[0][2] * local_n[0][1]);
    gsl_matrix_set(U_gsl, 13, 8, local_n[0][2] * local_n[0][2]);

    gsl_matrix_set(U_gsl, 13, 12, - local_n[0][0] * local_n[0][0]);
    gsl_matrix_set(U_gsl, 13, 13, - 2 * local_n[0][1] * local_n[0][0]);
    gsl_matrix_set(U_gsl, 13, 14, - 2 * local_n[0][2] * local_n[0][0]);
    gsl_matrix_set(U_gsl, 13, 15, - local_n[0][1] * local_n[0][1]);
    gsl_matrix_set(U_gsl, 13, 16, - 2 * local_n[0][2] * local_n[0][1]);
    gsl_matrix_set(U_gsl, 13, 17, - local_n[0][2] * local_n[0][2]);

    // Tangential stresses are zero

    gsl_matrix_set(U_gsl, 14, 3, - (local_n[0][0] * local_n[1][0]) );
    gsl_matrix_set(U_gsl, 14, 4, - (local_n[0][1] * local_n[1][0] + local_n[0][0] * local_n[1][1]) );
    gsl_matrix_set(U_gsl, 14, 5, - (local_n[0][2] * local_n[1][0] + local_n[0][0] * local_n[1][2]) );
    gsl_matrix_set(U_gsl, 14, 6, - (local_n[0][1] * local_n[1][1]) );
    gsl_matrix_set(U_gsl, 14, 7, - (local_n[0][2] * local_n[1][1] + local_n[0][1] * local_n[1][2]) );
    gsl_matrix_set(U_gsl, 14, 8, - (local_n[0][2] * local_n[1][2]) );

    gsl_matrix_set(U_gsl, 15, 3, - (local_n[0][0] * local_n[2][0]) );
    gsl_matrix_set(U_gsl, 15, 4, - (local_n[0][1] * local_n[2][0] + local_n[0][0] * local_n[2][1]) );
    gsl_matrix_set(U_gsl, 15, 5, - (local_n[0][2] * local_n[2][0] + local_n[0][0] * local_n[2][2]) );
    gsl_matrix_set(U_gsl, 15, 6, - (local_n[0][1] * local_n[2][1]) );
    gsl_matrix_set(U_gsl, 15, 7, - (local_n[0][2] * local_n[2][1] + local_n[0][1] * local_n[2][2]) );
    gsl_matrix_set(U_gsl, 15, 8, - (local_n[0][2] * local_n[2][2]) );


    gsl_matrix_set(U_gsl, 16, 12, - (local_n[0][0] * local_n[1][0]) );
    gsl_matrix_set(U_gsl, 16, 13, - (local_n[0][1] * local_n[1][0] + local_n[0][0] * local_n[1][1]) );
    gsl_matrix_set(U_gsl, 16, 14, - (local_n[0][2] * local_n[1][0] + local_n[0][0] * local_n[1][2]) );
    gsl_matrix_set(U_gsl, 16, 15, - (local_n[0][1] * local_n[1][1]) );
    gsl_matrix_set(U_gsl, 16, 16, - (local_n[0][2] * local_n[1][1] + local_n[0][1] * local_n[1][2]) );
    gsl_matrix_set(U_gsl, 16, 17, - (local_n[0][2] * local_n[1][2]) );

    gsl_matrix_set(U_gsl, 17, 12, - (local_n[0][0] * local_n[2][0]) );
    gsl_matrix_set(U_gsl, 17, 13, - (local_n[0][1] * local_n[2][0] + local_n[0][0] * local_n[2][1]) );
    gsl_matrix_set(U_gsl, 17, 14, - (local_n[0][2] * local_n[2][0] + local_n[0][0] * local_n[2][2]) );
    gsl_matrix_set(U_gsl, 17, 15, - (local_n[0][1] * local_n[2][1]) );
    gsl_matrix_set(U_gsl, 17, 16, - (local_n[0][2] * local_n[2][1] + local_n[0][1] * local_n[2][2]) );
    gsl_matrix_set(U_gsl, 17, 17, - (local_n[0][2] * local_n[2][2]) );


    // Tmp value for GSL solver
    int s;
    gsl_linalg_LU_decomp (U_gsl, p_gsl, &s);
    try
    {
        gsl_linalg_LU_solve (U_gsl, p_gsl, om_gsl, x_gsl);
    }
    catch (Exception& e)
    {
        cur_node.setContactCalculationError();
        for(int i = 0; i < 18; i++) {
            std::stringstream matStr;
            for(int j = 0; j < 18; j++)
                matStr << gsl_matrix_get(U_gsl, i, j) << " ";
            LOG_TRACE(matStr.str());
        }
        LOG_ERROR("Bad node: " << cur_node);
        LOG_ERROR("Normal: " << outer_normal[0] << " " << outer_normal[1] << " " << outer_normal[2]);
        LOG_ERROR("Delta: " << virt_node.coords[0] - cur_node.coords[0] 
                        << " " << virt_node.coords[1] - cur_node.coords[1] 
                        << " " << virt_node.coords[2] - cur_node.coords[2]);
        throw;
    }

    // Just get first 9 values (real node) and dump the rest 9 (virt node)
    for(int j = 0; j < 9; j++)
        new_node.values[j] = gsl_vector_get(x_gsl, j);
	
	CalcNode new_virt_node;
	for(int j = 0; j < 9; j++)
        new_virt_node.values[j] = gsl_vector_get(x_gsl, j + 9);
	
	if (isFreeBorder(new_node, new_virt_node, outer_normal))
    {
        fbc->doCalc(cur_node, new_node, matrix, previousNodes, inner, outer_normal, scale);
        return;
    }

};
void Vtu2TetrFileReader::readFile(string file, TetrMeshSecondOrder* mesh, GCMDispatcher* dispatcher, int rank, bool ignoreDispatcher)
{
    vtkXMLUnstructuredGridReader *xgr = vtkXMLUnstructuredGridReader::New();
    vtkUnstructuredGrid *g = vtkUnstructuredGrid::New();

    xgr->SetFileName(const_cast<char*>(file.c_str()));
    xgr->Update();

    g = xgr->GetOutput();
    if( ignoreDispatcher )
    {
        LOG_DEBUG("Reading file ignoring dispatcher");
    }
    else
    {
        LOG_DEBUG("Dispatcher zones:");
        dispatcher->printZones();
    }
    LOG_DEBUG("Number of points: " << g->GetNumberOfPoints());
    LOG_DEBUG("Number of cells: " << g->GetNumberOfCells());

    double v[3];
    vtkDoubleArray *vel = (vtkDoubleArray*) g->GetPointData()->GetArray("velocity");
    vel->SetNumberOfComponents(3);
    vtkDoubleArray *sxx = (vtkDoubleArray*) g->GetPointData()->GetArray("sxx");
    vtkDoubleArray *sxy = (vtkDoubleArray*) g->GetPointData()->GetArray("sxy");
    vtkDoubleArray *sxz = (vtkDoubleArray*) g->GetPointData()->GetArray("sxz");
    vtkDoubleArray *syy = (vtkDoubleArray*) g->GetPointData()->GetArray("syy");
    vtkDoubleArray *syz = (vtkDoubleArray*) g->GetPointData()->GetArray("syz");
    vtkDoubleArray *szz = (vtkDoubleArray*) g->GetPointData()->GetArray("szz");
    vtkIntArray *matId = (vtkIntArray*) g->GetPointData()->GetArray("materialID");
    vtkDoubleArray *rho = (vtkDoubleArray*) g->GetPointData()->GetArray("rho");
    vtkIntArray *nodeNumber = (vtkIntArray*) g->GetPointData ()->GetArray("nodeNumber");
    vtkIntArray *publicFlags = (vtkIntArray*) g->GetPointData ()->GetArray("publicFlags");
    vtkIntArray *privateFlags = (vtkIntArray*) g->GetPointData ()->GetArray("privateFlags");
    vtkIntArray *nodeBorderConditionId = (vtkIntArray*) g->GetPointData ()->GetArray("borderConditionId");

    vector<CalcNode*>* nodes = new vector<CalcNode*>;
    for( int i = 0; i < g->GetNumberOfPoints(); i++ )
    {
        double* dp = g->GetPoint(i);
        if( ignoreDispatcher || dispatcher->isMine( dp, mesh->getBody()->getId() ) )
        {
            CalcNode* node = new CalcNode();
            node->number = nodeNumber->GetValue(i);
            node->coords[0] = dp[0];
            node->coords[1] = dp[1];
            node->coords[2] = dp[2];
            vel->GetTupleValue(i, v);
            node->vx = v[0];
            node->vy = v[1];
            node->vz = v[2];
            node->sxx = sxx->GetValue(i);
            node->sxy = sxy->GetValue(i);
            node->sxz = sxz->GetValue(i);
            node->syy = syy->GetValue(i);
            node->syz = syz->GetValue(i);
            node->szz = szz->GetValue(i);
            node->setMaterialId( matId->GetValue(i) );
            node->setRho( rho->GetValue(i) );
            node->setPublicFlags( publicFlags->GetValue(i) );
            node->setPrivateFlags( privateFlags->GetValue(i) );
            node->setBorderConditionId( nodeBorderConditionId->GetValue(i) );
            if( !ignoreDispatcher )
                node->setPlacement(true);
            nodes->push_back( node );
        }
    }
    LOG_DEBUG("Finished reading nodes");
    LOG_DEBUG("There are " << nodes->size() << " local nodes");

    mesh->createNodes( nodes->size() );
    for(unsigned int i = 0; i < nodes->size(); i++)
    {
        mesh->addNode( *nodes->at(i) );
    }
    for(unsigned int i = 0; i < nodes->size(); i++)
    {
        delete( nodes->at(i));
    }
    nodes->clear();
    delete nodes;

    vtkIntArray* tetr2ndOrderNodes = (vtkIntArray*) g->GetCellData ()->GetArray ("tetr2ndOrderNodes");
    assert_eq(tetr2ndOrderNodes->GetNumberOfComponents (), 6);
    vtkIntArray* tetr1stOrderNodes = (vtkIntArray*) g->GetCellData ()->GetArray ("tetr1stOrderNodes");
    vtkIntArray* tetrNumber = (vtkIntArray*) g->GetCellData ()->GetArray ("tetrNumber");
    assert_eq(tetr1stOrderNodes->GetNumberOfComponents (), 4);
    vector<TetrSecondOrder*>* tetrs = new vector<TetrSecondOrder*>;

    TetrSecondOrder new_tetr;
    for( int i = 0; i < g->GetNumberOfCells(); i++ )
    {
        new_tetr.number = tetrNumber->GetValue(i);
        tetr1stOrderNodes->GetTupleValue (i, new_tetr.verts);
        tetr2ndOrderNodes->GetTupleValue (i, new_tetr.addVerts);

        /*vtkTetra *vt = (vtkTetra*) g->GetCell(i);

        int vert[4];
        vert[0] = vt->GetPointId(0);
        vert[1] = vt->GetPointId(1);
        vert[2] = vt->GetPointId(2);
        vert[3] = vt->GetPointId(3);*/

        if( mesh->hasNode(new_tetr.verts[0])
                    || mesh->hasNode(new_tetr.verts[1])
                    || mesh->hasNode(new_tetr.verts[2])
                    || mesh->hasNode(new_tetr.verts[3]) )
                tetrs->push_back( new TetrSecondOrder( new_tetr.number, new_tetr.verts, new_tetr.addVerts ) );
    }

    LOG_DEBUG("File contains " << g->GetNumberOfCells() << " tetrs");
    LOG_DEBUG("There are " << tetrs->size() << " local tetrs");

    map<int,int> remoteNodes;
    mesh->createTetrs( tetrs->size() );
    for(unsigned int i = 0; i < tetrs->size(); i++)
    {
        TetrSecondOrder* tetr = tetrs->at(i);
        mesh->addTetr2( *tetr );
        for(int j = 0; j < 4; j++)
            if( ! mesh->hasNode( tetr->verts[j] ) )
                remoteNodes[tetr->verts[j]] = i;
        for(int j = 0; j < 6; j++)
            if( ! mesh->hasNode( tetr->addVerts[j] ) )
                remoteNodes[tetr->addVerts[j]] = i;
    }
    for(unsigned int i = 0; i < tetrs->size(); i++)
    {
        delete( tetrs->at(i) );
    }
    tetrs->clear();
    delete tetrs;

    LOG_DEBUG("Finished reading elements");

    LOG_DEBUG("Reading required remote nodes");
    LOG_DEBUG("We expect " << remoteNodes.size() << " nodes" );
    int remoteNodesCount = 0;

    CalcNode tmpNode;
    for( int i = 0; i < g->GetNumberOfPoints(); i++ )
    {
        if( remoteNodes.find( nodeNumber->GetValue(i) ) != remoteNodes.end() )
        {
            double* dp = g->GetPoint(i);
            tmpNode.number = nodeNumber->GetValue(i);
            tmpNode.coords[0] = dp[0];
            tmpNode.coords[1] = dp[1];
            tmpNode.coords[2] = dp[2];
            vel->GetTupleValue(i, v);
            tmpNode.vx = v[0];
            tmpNode.vy = v[1];
            tmpNode.vz = v[2];
            tmpNode.sxx = sxx->GetValue(i);
            tmpNode.sxy = sxy->GetValue(i);
            tmpNode.sxz = sxz->GetValue(i);
            tmpNode.syy = syy->GetValue(i);
            tmpNode.syz = syz->GetValue(i);
            tmpNode.szz = szz->GetValue(i);
            tmpNode.setMaterialId( matId->GetValue(i) );
            tmpNode.setRho( rho->GetValue(i) );
            tmpNode.setPublicFlags( publicFlags->GetValue(i) );
            tmpNode.setPrivateFlags( privateFlags->GetValue(i) );
            tmpNode.setBorderConditionId( nodeBorderConditionId->GetValue(i) );
            tmpNode.setPlacement(false);
            mesh->addNode(tmpNode);
            remoteNodesCount++;
        }
    }

    LOG_DEBUG("Read " << remoteNodesCount << " remote nodes");

    LOG_DEBUG("Finished reading nodes");

    LOG_DEBUG("File successfylly read.");

    LOG_DEBUG("There are " << mesh->getNodesNumber() << " nodes is the mesh");

    LOG_DEBUG("Checking tetrs and nodes");

    for( int i = 0; i < mesh->getTetrsNumber(); i++ )
    {
        TetrSecondOrder& tetr = mesh->getTetr2ByLocalIndex(i);
        for (int j = 0; j < 4; j++)
            if ( ! mesh->hasNode(tetr.verts[j]) )
            {
                LOG_ERROR("Can not find node " << tetr.verts[j] << " required by local tetr " << i);
                THROW_BAD_MESH("Missed node");
            }
        for (int j = 0; j < 6; j++)
            if ( ! mesh->hasNode(tetr.addVerts[j]) )
            {
                LOG_ERROR("Can not find node " << tetr.addVerts[j] << " required by local tetr " << i);
                THROW_BAD_MESH("Missed node");
            }
    }

    //xgr->Delete();
    //g->Delete();
}
int InterpolationFixedAxis::find_nodes_on_previous_time_layer(CalcNode& cur_node, int stage, Mesh* mesh,
                                                                   float dksi[], bool inner[], vector<CalcNode>& previous_nodes,
                                                                   float outer_normal[], bool debug)
{
    LOG_TRACE("Start looking for nodes on previous time layer");
    
    // For all omegas
    for (int i = 0; i < 9; i++) {
        LOG_TRACE("Looking for characteristic " << i);
        // Check prevoius omegas ...
        bool already_found = false;
        for (int j = 0; j < i; j++) {
            // ... And try to find if we have already worked with the required point
            // on previous time layer (or at least with the point that is close enough)
            if (fabs(dksi[i] - dksi[j]) <= EQUALITY_TOLERANCE * 0.5 * fabs(dksi[i] + dksi[j])) {
                LOG_TRACE("Found old value " << dksi[i] << " - done");
                // If we have already worked with this point - just remember the number
                already_found = true;
                previous_nodes[i] = previous_nodes[j];
                inner[i] = inner[j];
            }
        }

        // If we do not have necessary point in place - ...
        if (!already_found) {
            LOG_TRACE("New value " << dksi[i] << " - preparing vectors");
            // ... Put new number ...
            previous_nodes[i] = cur_node;

            // ... Find vectors ...
            float dx[3];
            dx[0] = dx[1] = dx[2] = 0.0;
            dx[stage] += dksi[i];

            // For dksi = 0 we can skip check and just copy everything
            if (dksi[i] == 0) {
                // no interpolation required - everything is already in place
                inner[i] = true;
                LOG_TRACE("dksi is zero - done");
            }
            else if (cur_node.isInner()) {
                LOG_TRACE("Checking inner node");
                // ... Find owner tetrahedron ...
                bool isInnerPoint;
                mesh->interpolateNode(cur_node, dx[0], dx[1], dx[2], debug,
                                      previous_nodes[i], isInnerPoint);

                if (!isInnerPoint) {
                    LOG_TRACE("Inner node: we need new method here!");
                    LOG_TRACE("Node:\n" << cur_node);
                    LOG_TRACE("Move: " << dx[0] << " " << dx[1] << " " << dx[2]);
                    // TODO: return it back later
                    // Re-run search with debug on
                    //mesh->interpolateNode(origin, dx[0], dx[1], dx[2], true,
                    //                      previous_nodes[i], isInnerPoint);
                }

                inner[i] = true;
                LOG_TRACE("Checking inner node done");
            }
            else if (cur_node.isBorder()) {
                LOG_TRACE("Checking border node");
                // ... Find owner tetrahedron ...
                bool isInnerPoint;
                bool interpolated = mesh->interpolateNode(cur_node, dx[0], dx[1], dx[2], debug,
                                                          previous_nodes[i], isInnerPoint);

                // If we found inner point, it means
                // this direction is inner and everything works as for usual inner point
                if (isInnerPoint) {
                    inner[i] = true;
                    // If we did not find inner point - two cases are possible
                }
                else {
                    inner[i] = false;
                    // We found border cross somehow
                    // It can happen if we work with really thin structures and big time step
                    // We can work as usual in this case
                    if (interpolated) {
                        LOG_TRACE("Border node: we need new method here!");
                        inner[i] = true;
                        // Or we did not find any point at all - it means this characteristic is outer
                    }
                    else {
                        inner[i] = false;
                    }
                }
                LOG_TRACE("Checking border node done");
            }
            else {
                THROW_BAD_MESH("Unsupported case for characteristic location");
            }
        }
        LOG_TRACE("Looking for characteristic " << i << " done");
    }

    int outer_count = 0;
    for (int i = 0; i < 9; i++)
        if (!inner[i])
            outer_count++;

    // assert_true(outer_count == 0 || outer_count == 3);

    LOG_TRACE("Looking for nodes on previous time layer done. Outer count = " << outer_count);

    return outer_count;
}
void InterpolationFixedAxis::__doNextPartStep(CalcNode& cur_node, CalcNode& new_node, float time_step, int stage, Mesh* mesh)
{
    assert_ge(stage, 0);
    assert_le(stage, 2);

    auto& engine = Engine::getInstance();

    LOG_TRACE("Start node prepare for node " << cur_node.number);
    LOG_TRACE("Node: " << cur_node);

    // Variables used in calculations internally

    // Delta x on previous time layer for all the omegas
    //     omega_new_time_layer(ksi) = omega_old_time_layer(ksi+dksi)
    float dksi[9];

    // If the corresponding point on previous time layer is inner or not
    bool inner[9];

    // We will store interpolated nodes on previous time layer here
    // We know that we need five nodes for each direction (corresponding to Lambdas -C1, -C2, 0, C2, C1)
    // TODO  - We can  deal with (lambda == 0) separately
    vector<CalcNode> previous_nodes;
    previous_nodes.resize(9);

    // Outer normal at current point
    float outer_normal[3];

    // Number of outer characteristics
    int outer_count = prepare_node(cur_node, cur_node.getRheologyMatrix(),
                                   time_step, stage, mesh,
                                   dksi, inner, previous_nodes,
                                   outer_normal);

    LOG_TRACE("Done node prepare");

    // If all the omegas are 'inner'
    // omega = Matrix_OMEGA * u
    // new_u = Matrix_OMEGA^(-1) * omega
    // TODO - to think - if all omegas are 'inner' can we skip matrix calculations and just use new_u = interpolated_u ?
    if (cur_node.isInner()) {
        LOG_TRACE("Start inner node calc");
        if (outer_count == 0)
            // FIXME - hardcoded name
            engine.getVolumeCalculator("SimpleVolumeCalculator")->doCalc(
                                                                          new_node, cur_node.getRheologyMatrix(), previous_nodes);
        else
            THROW_BAD_MESH("Outer characteristic for internal node detected");
        LOG_TRACE("Done inner node calc");
    }

    if (cur_node.isBorder())
    {
        LOG_TRACE("Start border node calc");
        // FIXME_ASAP - do smth with this!
        // It is not stable now. See ugly hack below.
        // Think about: (a) cube, (b) rotated cube, (c) sphere.
        float val = (outer_normal[stage] >= 0 ? 1.0 : -1.0);
        outer_normal[0] = outer_normal[1] = outer_normal[2] = 0;
        outer_normal[stage] = val;
        // If there is no 'outer' omega - it is ok, border node can be inner for some directions
        if (outer_count == 0)
        {
            // FIXME - hardcoded name
            engine.getVolumeCalculator("SimpleVolumeCalculator")->doCalc(
                                                                          new_node, cur_node.getRheologyMatrix(), previous_nodes);
        }
            // If there are 3 'outer' omegas - we should use border or contact algorithm
        else if (outer_count == 3)
        {
            // Border
            if (!cur_node.isInContact() || cur_node.contactDirection != stage) {
                // FIXME
                int borderCondId = cur_node.getBorderConditionId();
                LOG_TRACE("Using calculator: " << engine.getBorderCondition(borderCondId)->calc->getType());
                engine.getBorderCondition(borderCondId)->doCalc(Engine::getInstance().getCurrentTime(), cur_node,
                                                                 new_node, cur_node.getRheologyMatrix(), previous_nodes, inner, outer_normal);
            }
            // Contact
            else
            {
                CalcNode& virt_node = engine.getVirtNode(cur_node.contactNodeNum);

                // FIXME - WA
                Mesh* virtMesh = (Mesh*) engine.getBody(virt_node.contactNodeNum)->getMeshes();

                LOG_TRACE("We are going to calc contact. Target virt node: "
                          << cur_node.contactNodeNum << " Target mesh: " << virt_node.contactNodeNum);

                LOG_TRACE("Mesh: " << mesh->getId()
                          << " Virt mesh: " << virtMesh->getId()
                          << "\nReal node: " << cur_node << "\nVirt node: " << virt_node);

                // Mark virt node as having contact state
                // TODO FIXME - most probably CollisionDetector should do it
                // But we should check it anycase
                virt_node.setInContact(true);
                //virt_node.contactNodeNum = cur_node.contactNodeNum;

                // Variables used in calculations internally

                // Delta x on previous time layer for all the omegas
                //     omega_new_time_layer(ksi) = omega_old_time_layer(ksi+dksi)
                float virt_dksi[9];

                // If the corresponding point on previous time layer is inner or not
                bool virt_inner[9];

                // We will store interpolated nodes on previous time layer here
                // We know that we need five nodes for each direction (corresponding to Lambdas -C1, -C2, 0, C2, C1)
                // TODO  - We can  deal with (lambda == 0) separately
                vector<CalcNode> virt_previous_nodes;
                virt_previous_nodes.resize(9);

                // Outer normal at current point
                float virt_outer_normal[3];

                // Number of outer characteristics
                int virt_outer_count = prepare_node(virt_node, virt_node.getRheologyMatrix(),
                                                    time_step, stage, virtMesh,
                                                    virt_dksi, virt_inner, virt_previous_nodes,
                                                    virt_outer_normal);

                // FIXME_ASAP: WA
                switch (stage) {
                case 0: virt_node.getRheologyMatrix()->decomposeX(virt_node);
                    break;
                case 1: virt_node.getRheologyMatrix()->decomposeY(virt_node);
                    break;
                case 2: virt_node.getRheologyMatrix()->decomposeZ(virt_node);
                    break;
                }
                
                // WA for sharp edges
                if(virt_outer_count == 0) {
                    RheologyMatrixPtr curM = cur_node.getRheologyMatrix();
                    RheologyMatrixPtr virtM = virt_node.getRheologyMatrix();
                    int sign = 0;
                    for(int i = 0; i < 9; i++) {
                        if(!inner[i])
                            sign = (curM->getL(i,i) > 0 ? 1 : -1);
                    }
                    for(int i = 0; i < 9; i++) {
                        if( virtM->getL(i,i) * sign < 0 )
                            virt_inner[i] = false;
                    }
                    virt_outer_count = 3;
                }

                // TODO - merge this condition with the next ones
                if (virt_outer_count != 3) {
                    LOG_DEBUG("EXTENDED DEBUG INFO BEGINS");
                    prepare_node(virt_node, virt_node.getRheologyMatrix(), time_step, stage, virtMesh, 
                                 virt_dksi, virt_inner, virt_previous_nodes, virt_outer_normal, true);
                    LOG_DEBUG("EXTENDED DEBUG INFO ENDS");
                    LOG_DEBUG("Calc contact failed. Mesh: " << mesh->getId()
                          << " Virt mesh: " << virtMesh->getId()
                          << "\nReal node: " << cur_node << "\nVirt node: " << virt_node);
                    LOG_DEBUG("There are " << virt_outer_count << " 'outer' characteristics for virt node.");
                    for (int z = 0; z < 9; z++) {
                        LOG_DEBUG("Dksi[" << z << "]: " << virt_dksi[z]);
                        LOG_DEBUG("Inner[" << z << "]: " << virt_inner[z]);
                        LOG_DEBUG("PrNodes[" << z << "]: " << virt_previous_nodes[z]);
                    }
                    THROW_BAD_METHOD("Illegal number of outer characteristics");
                }

                //                // Check that 'paired node' is in the direction of 'outer' characteristics
                //                // If it is not the case - we have strange situation when
                //                // we replace 'outer' points data with data of 'paired node' from different axis direction.
                //
                //                // For all characteristics of real node and virt node
                //                /*for(int i = 0; i < 9; i++)
                //                {
                //                    float v_x_outer[3];
                //                    float v_x_virt[3];
                //                    // Real node - if characteristic is 'outer'*/
                //    /*                if(!inner[i])
                //                    {
                //                        // Find directions to corresponding 'outer' point and to virt 'paired node'
                //                        for(int j = 0; j < 3; j++) {
                //                            v_x_outer[j] = previous_nodes[ppoint_num[i]].coords[j] - cur_node.coords[j];
                //                            v_x_virt[j] = virt_node.coords[j] - cur_node.coords[j];
                //                        }
                //                        // If directions are different - smth bad happens
                //                        if( (v_x_outer[0] * v_x_virt[0]
                //                             + v_x_outer[1] * v_x_virt[1] + v_x_outer[2] * v_x_virt[2]) < 0 )
                //                        {
                //                            *logger << "MESH " << mesh->zone_num << "REAL NODE " << cur_node.local_num << ": "
                //                                    << "x: " << cur_node.coords[0]
                //                                    << " y: " << cur_node.coords[1]
                //                                    << " z: " < cur_node.coords[2];
                //                            log_node_diagnostics(cur_node, stage, outer_normal, mesh, basis_num, rheologyMatrix, time_step, previous_nodes, ppoint_num, inner, dksi);
                //                            *logger << "'Outer' direction: " << v_x_outer[0] << " "
                //                                << v_x_outer[1] << " " < v_x_outer[2];
                //                            *logger << "'Virt' direction: " << v_x_virt[0] << " "
                //                                << v_x_virt[1] << " " < v_x_virt[2];
                //                            throw GCMException( GCMException::METHOD_EXCEPTION, "Bad contact from real node point of view: 'outer' and 'virt' directions are different");
                //                        }
                //                    }*/
                //    // We switch it off because it conflicts sometimes with 'safe_direction'
                //    /*                // Virt node - if characteristic is 'outer'
                //                    if(!virt_inner[i])
                //                    {
                //                        // Find directions to corresponding 'outer' point and to real 'paired node'
                //                        for(int j = 0; j < 3; j++) {
                //                            v_x_outer[j] = virt_previous_nodes[virt_ppoint_num[i]].coords[j] - virt_node.coords[j];
                //                            v_x_virt[j] = cur_node.coords[j] - virt_node.coords[j];
                //                        }
                //                        // If directions are different - smth bad happens
                //                        if( (v_x_outer[0] * v_x_virt[0]
                //                            + v_x_outer[1] * v_x_virt[1] + v_x_outer[2] * v_x_virt[2]) < 0 )
                //                        {
                //                            *logger << "MESH " << mesh->zone_num << "REAL NODE " << cur_node.local_num << ": "
                //                                    << "x: " << cur_node.coords[0]
                //                                    << " y: " << cur_node.coords[1]
                //                                    << " z: " < cur_node.coords[2];
                //                            log_node_diagnostics(virt_node, stage, virt_outer_normal, virt_node.mesh, basis_num, virt_rheologyMatrix, time_step, virt_previous_nodes, virt_ppoint_num, virt_inner, virt_dksi);
                //                            *logger << "'Outer' direction: " << v_x_outer[0] << " "
                //                                << v_x_outer[1] << " "< v_x_outer[2];
                //                            *logger << "'Virt' direction: " << v_x_virt[0] << " "
                //                                << v_x_virt[1] << " " < v_x_virt[2];
                //                            throw GCMException( GCMException::METHOD_EXCEPTION, "Bad contact from virt node point of view: 'outer' and 'virt' directions are different");
                //                        }
                //                    }*/
                ////                }
                //
                LOG_TRACE("Using calculator: " << engine.getContactCondition(cur_node.getContactConditionId())->calc->getType());
                LOG_TRACE("Outer normal: " << outer_normal[0] << " " << outer_normal[1] << " " << outer_normal[2]);
                engine.getContactCondition(cur_node.getContactConditionId())->doCalc(Engine::getInstance().getCurrentTime(), cur_node,
                                                       new_node, virt_node, cur_node.getRheologyMatrix(), previous_nodes, inner,
                                                       virt_node.getRheologyMatrix(), virt_previous_nodes, virt_inner, outer_normal);
            }
            // It means smth went wrong. Just interpolate the values and report bad node.
        }
        else
        {
            //LOG_WARN("Outer count: " << outer_count);
            //LOG_WARN("Node: " << cur_node);
            //for (int z = 0; z < 9; z++) {
            //    LOG_WARN("Dksi[" << z << "]: " << dksi[z]);
            //    LOG_WARN("Inner[" << z << "]: " << inner[z]);
            //    LOG_WARN("PrNodes[" << z << "]: " << previous_nodes[z]);
            //}
            //THROW_BAD_METHOD("Illegal number of outer characteristics");
            // FIXME - implement border and contact completely
            LOG_TRACE("Using calculator: " << engine.getBorderCondition(0)->calc->getType());
            engine.getBorderCondition(0)->doCalc(Engine::getInstance().getCurrentTime(), cur_node,
                                                  new_node, cur_node.getRheologyMatrix(), previous_nodes, inner, outer_normal);
            cur_node.setNeighError(stage);
        }
        LOG_TRACE("Done border node calc");
    }
}
void TetrFirstOrderInterpolator::interpolate(CalcNode& node, CalcNode& node0, CalcNode& node1, CalcNode& node2, CalcNode& node3)
{
    LOG_TRACE("Start interpolation");

    float Vol = tetrVolume(
                           (node1.coords[0])-(node0.coords[0]),
                           (node1.coords[1])-(node0.coords[1]),
                           (node1.coords[2])-(node0.coords[2]),
                           (node2.coords[0])-(node0.coords[0]),
                           (node2.coords[1])-(node0.coords[1]),
                           (node2.coords[2])-(node0.coords[2]),
                           (node3.coords[0])-(node0.coords[0]),
                           (node3.coords[1])-(node0.coords[1]),
                           (node3.coords[2])-(node0.coords[2])
                           );

    float factor[4];

    factor[0] = fabs(tetrVolume(
                                (node1.coords[0])-(node.coords[0]),
                                (node1.coords[1])-(node.coords[1]),
                                (node1.coords[2])-(node.coords[2]),
                                (node2.coords[0])-(node.coords[0]),
                                (node2.coords[1])-(node.coords[1]),
                                (node2.coords[2])-(node.coords[2]),
                                (node3.coords[0])-(node.coords[0]),
                                (node3.coords[1])-(node.coords[1]),
                                (node3.coords[2])-(node.coords[2])
                                ) / Vol);

    factor[1] = fabs(tetrVolume(
                                (node0.coords[0])-(node.coords[0]),
                                (node0.coords[1])-(node.coords[1]),
                                (node0.coords[2])-(node.coords[2]),
                                (node2.coords[0])-(node.coords[0]),
                                (node2.coords[1])-(node.coords[1]),
                                (node2.coords[2])-(node.coords[2]),
                                (node3.coords[0])-(node.coords[0]),
                                (node3.coords[1])-(node.coords[1]),
                                (node3.coords[2])-(node.coords[2])
                                ) / Vol);

    factor[2] = fabs(tetrVolume(
                                (node1.coords[0])-(node.coords[0]),
                                (node1.coords[1])-(node.coords[1]),
                                (node1.coords[2])-(node.coords[2]),
                                (node0.coords[0])-(node.coords[0]),
                                (node0.coords[1])-(node.coords[1]),
                                (node0.coords[2])-(node.coords[2]),
                                (node3.coords[0])-(node.coords[0]),
                                (node3.coords[1])-(node.coords[1]),
                                (node3.coords[2])-(node.coords[2])
                                ) / Vol);

    factor[3] = fabs(tetrVolume(
                                (node1.coords[0])-(node.coords[0]),
                                (node1.coords[1])-(node.coords[1]),
                                (node1.coords[2])-(node.coords[2]),
                                (node2.coords[0])-(node.coords[0]),
                                (node2.coords[1])-(node.coords[1]),
                                (node2.coords[2])-(node.coords[2]),
                                (node0.coords[0])-(node.coords[0]),
                                (node0.coords[1])-(node.coords[1]),
                                (node0.coords[2])-(node.coords[2])
                                ) / Vol);

    // If we see potential instability
    if (factor[0] + factor[1] + factor[2] + factor[3] > 1.0) {
        // If it is small - treat instability as minor and just 'smooth' it
        // TODO - think about it more carefully
        //if( point_in_tetr(node.local_num, node.coords[0], node.coords[1], node.coords[2], tetr) )
        if (factor[0] + factor[1] + factor[2] + factor[3] < 1.05) // FIXME@avasyukov
        {
            //if (factor[0] + factor[1] + factor[2] + factor[3] > 5.0)
            //    LOG_ERROR("Factor: " << factor[0] + factor[1] + factor[2] + factor[3]);
            float sum = factor[0] + factor[1] + factor[2] + factor[3];
            for (int i = 0; i < 4; i++)
                factor[i] = factor[i] / sum;
        }
            // If point is not in tetr - throw exception
        else {
            /*            *logger << "\tTetrVol = " < Vol;
             *logger << "\tfactor[0]=" << factor[0] << " factor[1]=" << factor[1] << " factor[2]=" << factor[2]     << " factor[3]=" << factor[3] << " Sum: " < factor[0] + factor[1] + factor[2] + factor[3];

             *logger << "\tnode.coords.x[0]=" << node.coords[0] << " node.coords.x[1]=" << node.coords[1]
                                            << " node.coords.x[2]=" < node.coords[2];
                                    if( node.isFirstOrder() )
             *logger < "First order node";
                                    else if( node.isSecondOrder() )
             *logger < "Second order node";

             *logger << "\tv0.x[0]=" << nodes[tetr.vert[0]].coords[0] << " v0.x[1]=" << nodes[tetr.vert[0]].coords[1] << " v0.x[2]=" < nodes[tetr.vert[0]].coords[2];

             *logger << "\tv1.x[0]=" << nodes[tetr.vert[1]].coords[0] << " v1.x[1]=" << nodes[tetr.vert[1]].coords[1] << " v1.x[2]=" < nodes[tetr.vert[1]].coords[2];

             *logger << "\tv2.x[0]=" << nodes[tetr.vert[2]].coords[0] << " v2.x[1]=" << nodes[tetr.vert[2]].coords[1] << " v2.x[2]=" < nodes[tetr.vert[2]].coords[2];

             *logger << "\tv3.x[0]=" << nodes[tetr.vert[3]].coords[0] << " v3.x[1]=" << nodes[tetr.vert[3]].coords[1] << " v3.x[2]=" < nodes[tetr.vert[3]].coords[2];*/
            LOG_ERROR("Requested node: " << node);
            LOG_ERROR("Node #1: " << node0);
            LOG_ERROR("Node #2: " << node1);
            LOG_ERROR("Node #3: " << node2);
            LOG_ERROR("Node #4: " << node3);
            LOG_ERROR("Factor: " << factor[0] + factor[1] + factor[2] + factor[3]);
            THROW_BAD_MESH("Sum of factors is greater than 1.0");
        }
    }

    for (int i = 0; i < 9; i++) {
        node.values[i] = (node0.values[i] * factor[0]
                + node1.values[i] * factor[1]
                + node2.values[i] * factor[2]
                + node3.values[i] * factor[3]);
    }

    node.setRho(node0.getRho() * factor[0] + node1.getRho() * factor[1]
                + node2.getRho() * factor[2] + node3.getRho() * factor[3]);
    node.setMaterialId(node0.getMaterialId());

    LOG_TRACE("Interpolation done");
}
Exemple #23
0
/**
 * Use the ColumnEditor dialog to edit the currently selected column
 * definition.  Called when the "Edit" button is pressed.
 */
void DBEditor::editColumn()
{
    QTreeWidgetItem *item = table->currentItem();
    if (!item) {
        return;
    }
    QString name = item->text(0);
    QString oldName = name;
    int index = info.Find(ceName [name.toUtf8()]);
    int type = ceType (info[index]);
    QString defaultVal = QString::fromUtf8(ceDefault (info[index]));

    columnEditor->setName(name);
    columnEditor->setType(type);
    columnEditor->setTypeEditable(false);
    columnEditor->setDefaultValue(defaultVal);
    CalcNode *calcRoot = 0;
    int decimals = 2;
    if (type == CALC) {
        calcRoot = calcMap[name];
        decimals = decimalsMap[name];
        // use a copy in case the edit is cancelled
        if (calcRoot != 0) {
            calcRoot = calcRoot->clone();
        }
        columnEditor->setCalculation(calcRoot, decimals);
    }
    bool finished = false;
    bool aborted = false;
    while (!finished) {
        if (!columnEditor->exec()) {
            finished = true;
            aborted = true;
        }
        else {
            name = columnEditor->name();
            type = columnEditor->type();
            defaultVal = columnEditor->defaultValue();
            if (name != oldName) {
                finished = (isValidName(name)
                            && isValidDefault(type, defaultVal));
                if (finished) {
                    int oldIndex = ceOldIndex (info[index]);
                    if (oldIndex != -1) {
                        renamedCols[oldIndex] = name;
                    }
                    renameColumnRefs(oldName, name);
                }
            }
            else {
                finished = isValidDefault(type, defaultVal);
            }
        }
    }
    calcRoot = columnEditor->calculation(&decimals);
    if (!aborted) {
        ceName (info[index]) = name.toUtf8();
        ceDefault (info[index]) = defaultVal.toUtf8();
        if (type == CALC) {
            CalcNode *oldRoot = calcMap[oldName];
            if (oldRoot != 0) {
                delete oldRoot;
            }
            calcMap.remove(oldName);
            decimalsMap.remove(oldName);
            calcMap.insert(name, calcRoot);
            decimalsMap.insert(name, decimals);
            columnEditor->setCalculation(0, 2);
            calcRoot = 0;
        }
        updateTable();
    }
    if (calcRoot != 0) {
        delete calcRoot;
        columnEditor->setCalculation(0, 2);
    }
}
void TetrSecondOrderMinMaxInterpolator::interpolate(CalcNode& node,
                                                         CalcNode& node0, CalcNode& node1, CalcNode& node2, CalcNode& node3,
                                                         CalcNode& addNode0, CalcNode& addNode1, CalcNode& addNode2,
                                                         CalcNode& addNode3, CalcNode& addNode4, CalcNode& addNode5)
{
    LOG_TRACE("Start interpolation");

    float factor[4];

    float Vol = tetrVolume(
                           (node1.coords[0])-(node0.coords[0]),
                           (node1.coords[1])-(node0.coords[1]),
                           (node1.coords[2])-(node0.coords[2]),
                           (node2.coords[0])-(node0.coords[0]),
                           (node2.coords[1])-(node0.coords[1]),
                           (node2.coords[2])-(node0.coords[2]),
                           (node3.coords[0])-(node0.coords[0]),
                           (node3.coords[1])-(node0.coords[1]),
                           (node3.coords[2])-(node0.coords[2])
                           );

    factor[0] = fabs(tetrVolume(
                                (node1.coords[0])-(node.coords[0]),
                                (node1.coords[1])-(node.coords[1]),
                                (node1.coords[2])-(node.coords[2]),
                                (node2.coords[0])-(node.coords[0]),
                                (node2.coords[1])-(node.coords[1]),
                                (node2.coords[2])-(node.coords[2]),
                                (node3.coords[0])-(node.coords[0]),
                                (node3.coords[1])-(node.coords[1]),
                                (node3.coords[2])-(node.coords[2])
                                ) / Vol);

    factor[1] = fabs(tetrVolume(
                                (node0.coords[0])-(node.coords[0]),
                                (node0.coords[1])-(node.coords[1]),
                                (node0.coords[2])-(node.coords[2]),
                                (node2.coords[0])-(node.coords[0]),
                                (node2.coords[1])-(node.coords[1]),
                                (node2.coords[2])-(node.coords[2]),
                                (node3.coords[0])-(node.coords[0]),
                                (node3.coords[1])-(node.coords[1]),
                                (node3.coords[2])-(node.coords[2])
                                ) / Vol);

    factor[2] = fabs(tetrVolume(
                                (node1.coords[0])-(node.coords[0]),
                                (node1.coords[1])-(node.coords[1]),
                                (node1.coords[2])-(node.coords[2]),
                                (node0.coords[0])-(node.coords[0]),
                                (node0.coords[1])-(node.coords[1]),
                                (node0.coords[2])-(node.coords[2]),
                                (node3.coords[0])-(node.coords[0]),
                                (node3.coords[1])-(node.coords[1]),
                                (node3.coords[2])-(node.coords[2])
                                ) / Vol);

    factor[3] = fabs(tetrVolume(
                                (node1.coords[0])-(node.coords[0]),
                                (node1.coords[1])-(node.coords[1]),
                                (node1.coords[2])-(node.coords[2]),
                                (node2.coords[0])-(node.coords[0]),
                                (node2.coords[1])-(node.coords[1]),
                                (node2.coords[2])-(node.coords[2]),
                                (node0.coords[0])-(node.coords[0]),
                                (node0.coords[1])-(node.coords[1]),
                                (node0.coords[2])-(node.coords[2])
                                ) / Vol);

    // If we see potential instability
    if (factor[0] + factor[1] + factor[2] + factor[3] > 1.0) {
        // If it is small - treat instability as minor and just 'smooth' it
        // TODO - think about it more carefully
        //if( point_in_tetr(node.local_num, node.coords[0], node.coords[1], node.coords[2], tetr) )
        if (factor[0] + factor[1] + factor[2] + factor[3] < 1.1) {
            float sum = factor[0] + factor[1] + factor[2] + factor[3];
            for (int i = 0; i < 4; i++)
                factor[i] = factor[i] / sum;
        }
            // If point is not in tetr - throw exception
        else {
            /*            *logger << "\tTetrVol = " < Vol;
             *logger << "\tfactor[0]=" << factor[0] << " factor[1]=" << factor[1] << " factor[2]=" << factor[2]     << " factor[3]=" << factor[3] << " Sum: " < factor[0] + factor[1] + factor[2] + factor[3];

             *logger << "\tnode.coords.x[0]=" << node.coords[0] << " node.coords.x[1]=" << node.coords[1]
                                            << " node.coords.x[2]=" < node.coords[2];
                                    if( node.isFirstOrder() )
             *logger < "First order node";
                                    else if( node.isSecondOrder() )
             *logger < "Second order node";

             *logger << "\tv0.x[0]=" << nodes[tetr.vert[0]].coords[0] << " v0.x[1]=" << nodes[tetr.vert[0]].coords[1] << " v0.x[2]=" < nodes[tetr.vert[0]].coords[2];

             *logger << "\tv1.x[0]=" << nodes[tetr.vert[1]].coords[0] << " v1.x[1]=" << nodes[tetr.vert[1]].coords[1] << " v1.x[2]=" < nodes[tetr.vert[1]].coords[2];

             *logger << "\tv2.x[0]=" << nodes[tetr.vert[2]].coords[0] << " v2.x[1]=" << nodes[tetr.vert[2]].coords[1] << " v2.x[2]=" < nodes[tetr.vert[2]].coords[2];

             *logger << "\tv3.x[0]=" << nodes[tetr.vert[3]].coords[0] << " v3.x[1]=" << nodes[tetr.vert[3]].coords[1] << " v3.x[2]=" < nodes[tetr.vert[3]].coords[2];*/
            THROW_BAD_MESH("Sum of factors is greater than 1.0");
        }
    }

    baseNodes[0] = &node0;
    baseNodes[1] = &node1;
    baseNodes[2] = &node2;
    baseNodes[3] = &node3;

    addNodes[0] = &addNode0;
    addNodes[1] = &addNode1;
    addNodes[2] = &addNode2;
    addNodes[3] = &addNode3;
    addNodes[4] = &addNode4;
    addNodes[5] = &addNode5;

    for (int i = 0; i < 9; i++) {
        float min = baseNodes[0]->values[i];
        float max = baseNodes[0]->values[i];
        for (int z = 1; z < 4; z++) {
            if (baseNodes[z]->values[i] < min)
                min = baseNodes[z]->values[i];
            if (baseNodes[z]->values[i] > max)
                max = baseNodes[z]->values[i];
        }
        for (int z = 0; z < 6; z++) {
            if (addNodes[z]->values[i] < min)
                min = addNodes[z]->values[i];
            if (addNodes[z]->values[i] > max)
                max = addNodes[z]->values[i];
        }

        node.values[i] = (baseNodes[0]->values[i] * factor[0] * (2 * factor[0] - 1)
                + baseNodes[1]->values[i] * factor[1] * (2 * factor[1] - 1)
                + baseNodes[2]->values[i] * factor[2] * (2 * factor[2] - 1)
                + baseNodes[3]->values[i] * factor[3] * (2 * factor[3] - 1)
                + addNodes[0]->values[i] * 4 * factor[0] * factor[1]
                + addNodes[1]->values[i] * 4 * factor[0] * factor[2]
                + addNodes[2]->values[i] * 4 * factor[0] * factor[3]
                + addNodes[3]->values[i] * 4 * factor[1] * factor[2]
                + addNodes[4]->values[i] * 4 * factor[1] * factor[3]
                + addNodes[5]->values[i] * 4 * factor[2] * factor[3]
                );

        if (node.values[i] < min)
            node.values[i] = min;
        if (node.values[i] > max)
            node.values[i] = max;
    }

    {
        float min = baseNodes[0]->getRho();
        float max = baseNodes[0]->getRho();
        for (int z = 1; z < 4; z++) {
            if (baseNodes[z]->getRho() < min)
                min = baseNodes[z]->getRho();
            if (baseNodes[z]->getRho() > max)
                max = baseNodes[z]->getRho();
        }
        for (int z = 0; z < 6; z++) {
            if (addNodes[z]->getRho() < min)
                min = addNodes[z]->getRho();
            if (addNodes[z]->getRho() > max)
                max = addNodes[z]->getRho();
        }

        float rho = (baseNodes[0]->getRho() * factor[0] * (2 * factor[0] - 1)
                + baseNodes[1]->getRho() * factor[1] * (2 * factor[1] - 1)
                + baseNodes[2]->getRho() * factor[2] * (2 * factor[2] - 1)
                + baseNodes[3]->getRho() * factor[3] * (2 * factor[3] - 1)
                + addNodes[0]->getRho() * 4 * factor[0] * factor[1]
                + addNodes[1]->getRho() * 4 * factor[0] * factor[2]
                + addNodes[2]->getRho() * 4 * factor[0] * factor[3]
                + addNodes[3]->getRho() * 4 * factor[1] * factor[2]
                + addNodes[4]->getRho() * 4 * factor[1] * factor[3]
                + addNodes[5]->getRho() * 4 * factor[2] * factor[3]
                );

        if (rho < min)
            rho = min;
        if (rho > max)
            rho = max;

        node.setRho(rho);
    }

    node.setMaterialId(baseNodes[0]->getMaterialId());

    LOG_TRACE("Interpolation done");
}
void VtuTetrFileReader::readFile(string file, TetrMeshFirstOrder* mesh, GCMDispatcher* dispatcher, int rank)
{
    vtkXMLUnstructuredGridReader *xgr = vtkXMLUnstructuredGridReader::New();
    vtkUnstructuredGrid *g = vtkUnstructuredGrid::New();

    xgr->SetFileName(const_cast<char*>(file.c_str()));
    xgr->Update();

    g = xgr->GetOutput();
    LOG_DEBUG("Number of points: " << g->GetNumberOfPoints());
    LOG_DEBUG("Number of cells: " << g->GetNumberOfCells());

    double v[3];
    vtkDoubleArray *vel = (vtkDoubleArray*) g->GetPointData()->GetArray("velocity");
    vel->SetNumberOfComponents(3);
    vtkDoubleArray *sxx = (vtkDoubleArray*) g->GetPointData()->GetArray("sxx");
    vtkDoubleArray *sxy = (vtkDoubleArray*) g->GetPointData()->GetArray("sxy");
    vtkDoubleArray *sxz = (vtkDoubleArray*) g->GetPointData()->GetArray("sxz");
    vtkDoubleArray *syy = (vtkDoubleArray*) g->GetPointData()->GetArray("syy");
    vtkDoubleArray *syz = (vtkDoubleArray*) g->GetPointData()->GetArray("syz");
    vtkDoubleArray *szz = (vtkDoubleArray*) g->GetPointData()->GetArray("szz");
    vtkIntArray *matId = (vtkIntArray*) g->GetPointData()->GetArray("materialID");
    vtkDoubleArray *rho = (vtkDoubleArray*) g->GetPointData()->GetArray("rho");
    vtkIntArray *publicFlags = (vtkIntArray*) g->GetPointData ()->GetArray("publicFlags");
    vtkIntArray *privateFlags = (vtkIntArray*) g->GetPointData ()->GetArray("privateFlags");

    vector<CalcNode*>* nodes = new vector<CalcNode*>;
    for( int i = 0; i < g->GetNumberOfPoints(); i++ )
    {
        double* dp = g->GetPoint(i);
        if( dispatcher->isMine( dp, mesh->getBody()->getId() ) )
        {
            CalcNode* node = new CalcNode();
            node->number = i;
            node->coords[0] = dp[0];
            node->coords[1] = dp[1];
            node->coords[2] = dp[2];
            vel->GetTupleValue(i, v);
            node->vx = v[0];
            node->vy = v[1];
            node->vz = v[2];
            node->sxx = sxx->GetValue(i);
            node->sxy = sxy->GetValue(i);
            node->sxz = sxz->GetValue(i);
            node->syy = syy->GetValue(i);
            node->syz = syz->GetValue(i);
            node->szz = szz->GetValue(i);
            node->setMaterialId( matId->GetValue(i) );
            node->setRho( rho->GetValue(i) );
            node->setPublicFlags( publicFlags->GetValue(i) );
            node->setPrivateFlags( privateFlags->GetValue(i) );
            node->setPlacement(true);
            nodes->push_back( node );
        }
    }
    LOG_DEBUG("Finished reading nodes");
    LOG_DEBUG("There are " << nodes->size() << " local nodes");

    mesh->createNodes( nodes->size() );
    for(unsigned int i = 0; i < nodes->size(); i++)
    {
        mesh->addNode( *nodes->at(i) );
    }
    nodes->clear();
    delete nodes;

    vector<TetrFirstOrder*>* tetrs = new vector<TetrFirstOrder*>;

    for( int i = 0; i < g->GetNumberOfCells(); i++ )
    {
        int number = tetrs->size();

        vtkTetra *vt = (vtkTetra*) g->GetCell(i);

        int vert[4];
        vert[0] = vt->GetPointId(0);
        vert[1] = vt->GetPointId(1);
        vert[2] = vt->GetPointId(2);
        vert[3] = vt->GetPointId(3);

        if( mesh->hasNode(vert[0])
                    || mesh->hasNode(vert[1])
                    || mesh->hasNode(vert[2])
                    || mesh->hasNode(vert[3]) )
                tetrs->push_back( new TetrFirstOrder( number, vert ) );
    }

    LOG_DEBUG("File contains " << g->GetNumberOfCells() << " tetrs");
    LOG_DEBUG("There are " << tetrs->size() << " local tetrs");

    map<int,int> remoteNodes;
    mesh->createTetrs( tetrs->size() );
    for(unsigned int i = 0; i < tetrs->size(); i++)
    {
        TetrFirstOrder* tetr = tetrs->at(i);
        mesh->addTetr( *tetr );
        for(int j = 0; j < 4; j++)
            if( ! mesh->hasNode( tetr->verts[j] ) )
                remoteNodes[tetr->verts[j]] = i;
    }
    tetrs->clear();
    delete tetrs;

    LOG_DEBUG("Finished reading elements");

    LOG_DEBUG("Reading required remote nodes");
    LOG_DEBUG("We expect " << remoteNodes.size() << " nodes" );
    int remoteNodesCount = 0;

    CalcNode tmpNode;
    for( int i = 0; i < g->GetNumberOfPoints(); i++ )
    {
        if( remoteNodes.find( i ) != remoteNodes.end() )
        {
            double* dp = g->GetPoint(i);
            tmpNode.number = i;
            tmpNode.coords[0] = dp[0];
            tmpNode.coords[1] = dp[1];
            tmpNode.coords[2] = dp[2];
            vel->GetTupleValue(i, v);
            tmpNode.vx = v[0];
            tmpNode.vy = v[1];
            tmpNode.vz = v[2];
            tmpNode.sxx = sxx->GetValue(i);
            tmpNode.sxy = sxy->GetValue(i);
            tmpNode.sxz = sxz->GetValue(i);
            tmpNode.syy = syy->GetValue(i);
            tmpNode.syz = syz->GetValue(i);
            tmpNode.szz = szz->GetValue(i);
            tmpNode.setMaterialId( matId->GetValue(i) );
            tmpNode.setRho( rho->GetValue(i) );
            tmpNode.setPublicFlags( publicFlags->GetValue(i) );
            tmpNode.setPrivateFlags( privateFlags->GetValue(i) );
            tmpNode.setPlacement(false);
            mesh->addNode(tmpNode);
            remoteNodesCount++;
        }
    }

    LOG_DEBUG("Read " << remoteNodesCount << " remote nodes");

    LOG_DEBUG("Finished reading nodes");

    LOG_DEBUG("File successfylly read.");

    LOG_DEBUG("There are " << mesh->getNodesNumber() << " nodes is the mesh");
}