Chaste Commit::29c3c4ab2bee00ddd311a035a1e522c03cbe928a
AbstractContinuumMechanicsSolver.hpp
1/*
2
3Copyright (c) 2005-2026, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#ifndef ABSTRACTCONTINUUMMECHANICSSOLVER_HPP_
37#define ABSTRACTCONTINUUMMECHANICSSOLVER_HPP_
38
39#include "ContinuumMechanicsProblemDefinition.hpp"
40#include "CompressibilityType.hpp"
41#include "LinearSystem.hpp"
42#include "OutputFileHandler.hpp"
43#include "ReplicatableVector.hpp"
44#include "AbstractTetrahedralMesh.hpp"
45#include "QuadraticMesh.hpp"
46#include "DistributedQuadraticMesh.hpp"
47#include "Warnings.hpp"
48#include "PetscException.hpp"
49#include "GaussianQuadratureRule.hpp"
50#include "PetscTools.hpp"
51#include "MechanicsEventHandler.hpp"
52#include "CommandLineArguments.hpp"
53#include "VtkMeshWriter.hpp"
54
55
61typedef enum _ApplyDirichletBcsType
62{
63 LINEAR_PROBLEM,
64 NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY,
65 NONLINEAR_PROBLEM_APPLY_TO_EVERYTHING
66} ApplyDirichletBcsType;
67
68//forward declarations
69template<unsigned DIM> class StressRecoveror;
70template<unsigned DIM> class VtkNonlinearElasticitySolutionWriter;
71
86template<unsigned DIM>
88{
89 friend class StressRecoveror<DIM>;
91
92protected:
98
101
104
106 std::string mOutputDirectory;
107
110
114 std::vector<c_vector<double,DIM> > mSpatialSolution;
115
117 std::vector<double> mPressureSolution;
118
119
126 std::vector<double> mCurrentSolution;
127
130
133
138 CompressibilityType mCompressibilityType;
139
149
153 unsigned mNumDofs;
154
161
183
188
193
198
203
208
209
235 void ApplyDirichletBoundaryConditions(ApplyDirichletBcsType type, bool symmetricProblem);
236
269 void AddIdentityBlockForDummyPressureVariables(ApplyDirichletBcsType type);
270
271
289
290public:
300 std::string outputDirectory,
301 CompressibilityType compressibilityType);
302
305
317 void WriteCurrentSpatialSolution(std::string fileName, std::string fileExtension, int counterToAppend=-1);
318
331 void WriteCurrentPressureSolution( int counterToAppend=-1);
332
338 void SetWriteOutput(bool writeOutput=true);
339
347 void CreateVtkOutput(std::string spatialSolutionName="Spatial solution");
348
353 std::vector<double>& rGetCurrentSolution()
354 {
355 return mCurrentSolution;
356 }
357
362 virtual std::vector<c_vector<double,DIM> >& rGetSpatialSolution()=0;
363
372 std::vector<double>& rGetPressures();
373};
374
375template<unsigned DIM>
378 std::string outputDirectory,
379 CompressibilityType compressibilityType)
380 : mrQuadMesh(rQuadMesh),
381 mrProblemDefinition(rProblemDefinition),
382 mOutputDirectory(outputDirectory),
383 mpOutputFileHandler(nullptr),
384 mpQuadratureRule(nullptr),
385 mpBoundaryQuadratureRule(nullptr),
386 mCompressibilityType(compressibilityType),
387 mResidualVector(nullptr),
388 mSystemLhsMatrix(nullptr),
389 mPreconditionMatrix(nullptr)
390{
391 assert(DIM==2 || DIM==3);
392
393 //Check that the mesh is Quadratic
394 QuadraticMesh<DIM>* p_quad_mesh = dynamic_cast<QuadraticMesh<DIM>* >(&rQuadMesh);
395 DistributedQuadraticMesh<DIM>* p_distributed_quad_mesh = dynamic_cast<DistributedQuadraticMesh<DIM>* >(&rQuadMesh);
396
397 if ((p_quad_mesh == nullptr) && (p_distributed_quad_mesh == nullptr))
398 {
399 EXCEPTION("Continuum mechanics solvers require a quadratic mesh");
400 }
401
402
403 mVerbose = (mrProblemDefinition.GetVerboseDuringSolve() ||
404 CommandLineArguments::Instance()->OptionExists("-mech_verbose") ||
405 CommandLineArguments::Instance()->OptionExists("-mech_very_verbose") );
406
408 if (mWriteOutput)
409 {
411 }
412
413 // See dox for mProblemDimension
414 mProblemDimension = mCompressibilityType==COMPRESSIBLE ? DIM : DIM+1;
416
418
419 // In general the Jacobian for a mechanics problem is non-polynomial.
420 // We therefore use the highest order integration rule available.
422 // The boundary forcing terms (or tractions) are also non-polynomial in general.
423 // Again, we use the highest order integration rule available.
425
426 mCurrentSolution.resize(mNumDofs, 0.0);
427}
428
429template<unsigned DIM>
431{
432 if (mpOutputFileHandler)
433 {
434 delete mpOutputFileHandler;
435 }
436
437 if (mpQuadratureRule)
438 {
439 delete mpQuadratureRule;
440 delete mpBoundaryQuadratureRule;
441 }
442
443 if (mResidualVector)
444 {
445 PetscTools::Destroy(mResidualVector);
446 PetscTools::Destroy(mLinearSystemRhsVector);
447 PetscTools::Destroy(mSystemLhsMatrix);
448 PetscTools::Destroy(mPreconditionMatrix);
449 }
450
451 if (mDirichletBoundaryConditionsVector)
452 {
453 PetscTools::Destroy(mDirichletBoundaryConditionsVector);
454 }
455}
456
457template<unsigned DIM>
459 std::string fileExtension,
460 int counterToAppend)
461{
462 // Only write output if the flag mWriteOutput has been set
463 if (!mWriteOutput)
464 {
465 return;
466 }
467
469 {
470 std::stringstream file_name;
471
472 file_name << fileName;
473 if (counterToAppend >= 0)
474 {
475 file_name << "_" << counterToAppend;
476 }
477 file_name << "." << fileExtension;
478
479 out_stream p_file = mpOutputFileHandler->OpenOutputFile(file_name.str());
480
481 std::vector<c_vector<double,DIM> >& r_spatial_solution = rGetSpatialSolution();
482 for (unsigned i=0; i<r_spatial_solution.size(); i++)
483 {
484 // for (unsigned j=0; j<DIM; j++)
485 // {
486 // *p_file << mrQuadMesh.GetNode(i)->rGetLocation()[j] << " ";
487 // }
488 for (unsigned j=0; j<DIM; j++)
489 {
490 *p_file << r_spatial_solution[i](j) << " ";
491 }
492 *p_file << "\n";
493 }
494 p_file->close();
495 }
496 PetscTools::Barrier("WriteSpatial");
497}
498
499template<unsigned DIM>
501{
502 // Only write output if the flag mWriteOutput has been set
503 if (mWriteOutput)
504 {
505 // Only the master writes
506 if (PetscTools::AmMaster() && mWriteOutput)
507 {
508 std::stringstream file_name;
509
510 file_name << "pressure";
511 if (counterToAppend >= 0)
512 {
513 file_name << "_" << counterToAppend;
514 }
515 file_name << ".txt";
516
517 out_stream p_file = mpOutputFileHandler->OpenOutputFile(file_name.str());
518
519 std::vector<double> &r_pressure = rGetPressures();
520 for (unsigned i = 0; i < r_pressure.size(); i++)
521 {
522 for (unsigned j = 0; j < DIM; j++)
523 {
524 *p_file << mrQuadMesh.GetNode(i)->rGetLocation()[j] << " ";
525 }
526
527 *p_file << r_pressure[i] << "\n";
528 }
529 p_file->close();
530 }
531 PetscTools::Barrier("WritePressure");
532 }
533}
534
535template<unsigned DIM>
537{
538 if (writeOutput && (mOutputDirectory==""))
539 {
540 EXCEPTION("Can't write output if no output directory was given in constructor");
541 }
542 mWriteOutput = writeOutput;
543}
544
545// ** TO BE DEPRECATED - see #2321 **
546template<unsigned DIM>
548{
549 if (this->mOutputDirectory=="")
550 {
551 EXCEPTION("No output directory was given so no output was written, cannot convert to VTK format");
552 }
553 VtkMeshWriter<DIM, DIM> mesh_writer(this->mOutputDirectory + "/vtk", "solution", true);
554
555 mesh_writer.AddPointData(spatialSolutionName, this->rGetSpatialSolution());
556
557 if (mCompressibilityType==INCOMPRESSIBLE)
558 {
559 mesh_writer.AddPointData("Pressure", rGetPressures());
560 }
561
562 //Output the element attribute as cell data.
563 std::vector<double> element_attribute;
564 for (typename QuadraticMesh<DIM>::ElementIterator iter = this->mrQuadMesh.GetElementIteratorBegin();
565 iter != this->mrQuadMesh.GetElementIteratorEnd();
566 ++iter)
567 {
568 element_attribute.push_back(iter->GetAttribute());
569 }
570 mesh_writer.AddCellData("Attribute", element_attribute);
571
572 mesh_writer.WriteFilesUsingMesh(this->mrQuadMesh);
573}
574
575template<unsigned DIM>
577{
578 assert(mProblemDimension==DIM+1);
579
580 mPressureSolution.clear();
581 mPressureSolution.resize(mrQuadMesh.GetNumNodes());
582
583 for (unsigned i=0; i<mrQuadMesh.GetNumNodes(); i++)
584 {
585 mPressureSolution[i] = mCurrentSolution[mProblemDimension*i + DIM];
586 }
587 return mPressureSolution;
588}
589
590template<unsigned DIM>
592{
593 assert(mProblemDimension==DIM+1);
594
595 // For quadratic triangles, node 3 is between nodes 1 and 2, node 4 is between 0 and 2, etc
596 unsigned internal_nodes_2d[3] = {3,4,5};
597 unsigned neighbouring_vertices_2d[3][2] = { {1,2}, {2,0}, {0,1} };
598
599 // ordering for quadratic tetrahedra
600 unsigned internal_nodes_3d[6] = {4,5,6,7,8,9};
601 unsigned neighbouring_vertices_3d[6][2] = { {0,1}, {1,2}, {0,2}, {0,3}, {1,3}, {2,3} };
602
603 unsigned num_internal_nodes_per_element = DIM==2 ? 3 : 6;
604
605 // loop over elements, then loop over edges.
606 for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = mrQuadMesh.GetElementIteratorBegin();
607 iter != mrQuadMesh.GetElementIteratorEnd();
608 ++iter)
609 {
610 for (unsigned i=0; i<num_internal_nodes_per_element; i++)
611 {
612 unsigned global_index;
613 double left_val;
614 double right_val;
615
616 if (DIM == 2)
617 {
618 global_index = iter->GetNodeGlobalIndex( internal_nodes_2d[i] );
619 unsigned vertex_0_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_2d[i][0] );
620 unsigned vertex_1_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_2d[i][1] );
621 left_val = mCurrentSolution[mProblemDimension*vertex_0_global_index + DIM];
622 right_val = mCurrentSolution[mProblemDimension*vertex_1_global_index + DIM];
623 }
624 else
625 {
626 global_index = iter->GetNodeGlobalIndex( internal_nodes_3d[i] );
627 unsigned vertex_0_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_3d[i][0] );
628 unsigned vertex_1_global_index =iter->GetNodeGlobalIndex( neighbouring_vertices_3d[i][1] );
629 left_val = mCurrentSolution[mProblemDimension*vertex_0_global_index + DIM];
630 right_val = mCurrentSolution[mProblemDimension*vertex_1_global_index + DIM];
631 }
632
633 // this line assumes the internal node is midway between the two vertices
634 mCurrentSolution[mProblemDimension*global_index + DIM] = 0.5 * (left_val + right_val);
635 }
636 }
637}
638
639/*
640 * This method applies the appropriate BCs to the residual and/or linear system
641 *
642 * For the latter, and second input parameter==true, the BCs are imposed in such a way as
643 * to ensure that a symmetric linear system remains symmetric. For each row with boundary condition
644 * applied, both the row and column are zero'd and the RHS vector modified to take into account the
645 * zero'd column.
646 *
647 * Suppose we have a matrix
648 * [a b c] [x] = [ b1 ]
649 * [d e f] [y] [ b2 ]
650 * [g h i] [z] [ b3 ]
651 * and we want to apply the boundary condition x=v without losing symmetry if the matrix is
652 * symmetric. We apply the boundary condition
653 * [1 0 0] [x] = [ v ]
654 * [d e f] [y] [ b2 ]
655 * [g h i] [z] [ b3 ]
656 * and then zero the column as well, adding a term to the RHS to take account for the
657 * zero-matrix components
658 * [1 0 0] [x] = [ v ] - v[ 0 ]
659 * [0 e f] [y] [ b2 ] [ d ]
660 * [0 h i] [z] [ b3 ] [ g ]
661 * Note the last term is the first column of the matrix, with one component zeroed, and
662 * multiplied by the boundary condition value. This last term is then stored in
663 * mDirichletBoundaryConditionsVector, and in general is equal to:
664 * SUM_{d=1..D} v_d a'_d
665 * where v_d is the boundary value of boundary condition d (d an index into the matrix),
666 * and a'_d is the dth-column of the matrix but with the d-th component zeroed, and where
667 * there are D boundary conditions
668 */
669template<unsigned DIM>
670void AbstractContinuumMechanicsSolver<DIM>::ApplyDirichletBoundaryConditions(ApplyDirichletBcsType type, bool symmetricProblem)
671{
672 std::vector<unsigned> rows;
673 std::vector<double> values;
674
675 // Whether to apply symmetrically, ie alter columns as well as rows (see comment above)
676 bool applySymmetrically = (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY) && symmetricProblem;
677
678 if (applySymmetrically)
679 {
680 if (mDirichletBoundaryConditionsVector == nullptr)
681 {
682 VecDuplicate(mResidualVector, &mDirichletBoundaryConditionsVector);
683 }
684
685 PetscVecTools::Zero(mDirichletBoundaryConditionsVector);
686 PetscMatTools::Finalise(mSystemLhsMatrix);
687 }
688
690 // collect the entries to be altered
692
693 for (unsigned i=0; i<mrProblemDefinition.rGetDirichletNodes().size(); i++)
694 {
695 unsigned node_index = mrProblemDefinition.rGetDirichletNodes()[i];
696
697 for (unsigned j=0; j<DIM; j++)
698 {
699 double dirichlet_val = mrProblemDefinition.rGetDirichletNodeValues()[i](j);
700
702 {
703 double val;
704 unsigned dof_index = mProblemDimension*node_index+j;
705
706 if (type == LINEAR_PROBLEM)
707 {
708 val = dirichlet_val;
709 }
710 else
711 {
712 // The boundary conditions on the NONLINEAR SYSTEM are x=boundary_values
713 // on the boundary nodes. However:
714 // The boundary conditions on the LINEAR SYSTEM at each Newton step (Ju=f,
715 // where J is the Jacobian, u the negative update vector and f is the residual) is:
716 // u=current_soln-boundary_values on the boundary nodes
717 val = mCurrentSolution[dof_index] - dirichlet_val;
718 }
719 rows.push_back(dof_index);
720 values.push_back(val);
721 }
722 }
723 }
724
726 // do the alterations
728
729 if (applySymmetrically)
730 {
731 // Modify the matrix columns
732 for (unsigned i=0; i<rows.size(); i++)
733 {
734 unsigned col = rows[i];
735 double minus_value = -values[i];
736
737 // Get a vector which will store the column of the matrix (column d, where d is
738 // the index of the row (and column) to be altered for the boundary condition.
739 // Since the matrix is symmetric when get row number "col" and treat it as a column.
740 // PETSc uses compressed row format and therefore getting rows is far more efficient
741 // than getting columns.
742 Vec matrix_col = PetscMatTools::GetMatrixRowDistributed(mSystemLhsMatrix,col);
743
744 // Zero the correct entry of the column
745 PetscVecTools::SetElement(matrix_col, col, 0.0);
746
747 // Set up the RHS Dirichlet boundary conditions vector
748 // E.g. for a boundary node at the zeroth node (x_0 = value), this is equal to
749 // -value*[0 a_21 a_31 .. a_N1]
750 // and will be added to the RHS.
751 PetscVecTools::Finalise(matrix_col); //PETSc 3.19 doesn't like mixing "set" mode (above) with "add" mode
752 PetscVecTools::AddScaledVector(mDirichletBoundaryConditionsVector, matrix_col, minus_value);
753 PetscTools::Destroy(matrix_col);
754 }
755 }
756
757 if (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY) // i.e. doing a whole linear system
758 {
759 // Now zero the appropriate rows and columns of the matrix. If the matrix is symmetric we apply the
760 // boundary conditions in a way the symmetry isn't lost (rows and columns). If not only the row is
761 // zeroed.
762 if (applySymmetrically)
763 {
764 PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mSystemLhsMatrix, rows, 1.0);
765 PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
766
767 // Apply the RHS boundary conditions modification if required.
768 // (AddScaledVector now needs assembly to be finalised.)
769 PetscVecTools::Finalise(mLinearSystemRhsVector);
770 PetscVecTools::AddScaledVector(mLinearSystemRhsVector, mDirichletBoundaryConditionsVector, 1.0);
771 }
772 else
773 {
774 PetscMatTools::ZeroRowsWithValueOnDiagonal(mSystemLhsMatrix, rows, 1.0);
775 PetscMatTools::ZeroRowsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
776 }
777 }
778
779 if (type!=LINEAR_PROBLEM)
780 {
781 for (unsigned i=0; i<rows.size(); i++)
782 {
783 PetscVecTools::SetElement(mResidualVector, rows[i], values[i]);
784 }
785 }
786
787 if (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY)
788 {
789 for (unsigned i=0; i<rows.size(); i++)
790 {
791 PetscVecTools::SetElement(mLinearSystemRhsVector, rows[i], values[i]);
792 }
793 }
794}
795
796template<unsigned DIM>
798{
799 assert(mCompressibilityType==INCOMPRESSIBLE);
800
801 int lo, hi;
802 VecGetOwnershipRange(mResidualVector, &lo, &hi);
803
804 for (unsigned i=0; i<mrQuadMesh.GetNumNodes(); i++)
805 {
806 if (mrQuadMesh.GetNode(i)->IsInternal())
807 {
808 unsigned row = (DIM+1)*i + DIM; // DIM+1 is the problem dimension
809 if (lo <= (int)row && (int)row < hi)
810 {
811 if (type!=LINEAR_PROBLEM)
812 {
813 PetscVecTools::SetElement(mResidualVector, row, mCurrentSolution[row]-0.0);
814 }
815 if (type!=NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY) // ie doing a whole linear system
816 {
817 double rhs_vector_val = type==LINEAR_PROBLEM ? 0.0 : mCurrentSolution[row]-0.0;
818 PetscVecTools::SetElement(mLinearSystemRhsVector, row, rhs_vector_val);
819 // This assumes the row is already zero, which is should be..
820 PetscMatTools::SetElement(mSystemLhsMatrix, row, row, 1.0);
821 PetscMatTools::SetElement(mPreconditionMatrix, row, row, 1.0);
822 }
823 }
824 }
825 }
826}
827
828template<unsigned DIM>
830{
831 Vec template_vec = mrQuadMesh.GetDistributedVectorFactory()->CreateVec(mProblemDimension);
832
834 // three vectors
836 VecDuplicate(template_vec, &mResidualVector);
837 VecDuplicate(mResidualVector, &mLinearSystemRhsVector);
838 // the one is only allocated if it will be needed (in ApplyDirichletBoundaryConditions),
839 // depending on whether the matrix is kept symmetric.
840 mDirichletBoundaryConditionsVector = nullptr;
841 PetscTools::Destroy(template_vec);
842
844 // two matrices
846
847 int lo, hi;
848 VecGetOwnershipRange(mResidualVector, &lo, &hi);
849 PetscInt local_size = hi - lo;
850
851
852 if (DIM==2)
853 {
854 // 2D: N elements around a point => 7N+3 non-zeros in that row? Assume N<=10 (structured mesh would have N_max=6) => 73.
855 unsigned num_non_zeros = std::min(75u, mNumDofs);
856
857 PetscTools::SetupMat(mSystemLhsMatrix, mNumDofs, mNumDofs, num_non_zeros, local_size, local_size);
858 PetscTools::SetupMat(mPreconditionMatrix, mNumDofs, mNumDofs, num_non_zeros, local_size, local_size);
859 }
860 else
861 {
862 assert(DIM==3);
863
864 // in 3d we get the number of containing elements for each node and use that to obtain an upper bound
865 // for the number of non-zeros for each DOF associated with that node.
866
867 int* num_non_zeros_each_row = new int[mNumDofs];
868 for (unsigned i=0; i<mNumDofs; i++)
869 {
870 num_non_zeros_each_row[i] = 0;
871 }
872
873 for (typename AbstractMesh<DIM,DIM>::NodeIterator iter = mrQuadMesh.GetNodeIteratorBegin();
874 iter != mrQuadMesh.GetNodeIteratorEnd();
875 ++iter)
876 {
877 // this upper bound neglects the fact that two containing elements will share the same nodes..
878 // 4 = max num dofs associated with this node
879 // 30 = 3*9+3 = 3 dimensions x 9 other nodes on this element + 3 vertices with a pressure unknown
880 unsigned num_non_zeros_upper_bound = 4 + 30*iter->GetNumContainingElements();
881
882 num_non_zeros_upper_bound = std::min(num_non_zeros_upper_bound, mNumDofs);
883
884 unsigned i = iter->GetIndex();
885
886 num_non_zeros_each_row[mProblemDimension*i + 0] = num_non_zeros_upper_bound;
887 num_non_zeros_each_row[mProblemDimension*i + 1] = num_non_zeros_upper_bound;
888 num_non_zeros_each_row[mProblemDimension*i + 2] = num_non_zeros_upper_bound;
889
890 if (mCompressibilityType==INCOMPRESSIBLE)
891 {
892 if (!iter->IsInternal())
893 {
894 num_non_zeros_each_row[mProblemDimension*i + 3] = num_non_zeros_upper_bound;
895 }
896 else
897 {
898 num_non_zeros_each_row[mProblemDimension*i + 3] = 1;
899 }
900 }
901 }
902
903 // NOTE: PetscTools::SetupMat() or the below creates a MATAIJ matrix, which means the matrix will
904 // be of type MATSEQAIJ if num_procs=1 and MATMPIAIJ otherwise. In the former case
905 // MatSeqAIJSetPreallocation MUST be called [MatMPIAIJSetPreallocation will have
906 // no effect (silently)], and vice versa in the latter case
907
910 //PetscTools::SetupMat(mSystemLhsMatrix, mNumDofs, mNumDofs, 0, PETSC_DECIDE, PETSC_DECIDE);
911 //PetscTools::SetupMat(mPreconditionMatrix, mNumDofs, mNumDofs, 0, PETSC_DECIDE, PETSC_DECIDE);
913
914 // possible todo: create a PetscTools::SetupMatNoAllocation()
915
916
917#if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
918 MatCreate(PETSC_COMM_WORLD,local_size,local_size,mNumDofs,mNumDofs,&mSystemLhsMatrix);
919 MatCreate(PETSC_COMM_WORLD,local_size,local_size,mNumDofs,mNumDofs,&mPreconditionMatrix);
920#else //New API
921 MatCreate(PETSC_COMM_WORLD,&mSystemLhsMatrix);
922 MatCreate(PETSC_COMM_WORLD,&mPreconditionMatrix);
923 MatSetSizes(mSystemLhsMatrix,local_size,local_size,mNumDofs,mNumDofs);
924 MatSetSizes(mPreconditionMatrix,local_size,local_size,mNumDofs,mNumDofs);
925#endif
926
928 {
929 MatSetType(mSystemLhsMatrix, MATSEQAIJ);
930 MatSetType(mPreconditionMatrix, MATSEQAIJ);
931 MatSeqAIJSetPreallocation(mSystemLhsMatrix, PETSC_DEFAULT, num_non_zeros_each_row);
932 MatSeqAIJSetPreallocation(mPreconditionMatrix, PETSC_DEFAULT, num_non_zeros_each_row);
933 }
934 else
935 {
936 int* num_non_zeros_each_row_in_diag = new int[local_size];
937 int* num_non_zeros_each_row_off_diag = new int[local_size];
938 for (unsigned i=0; i<unsigned(local_size); i++)
939 {
940 num_non_zeros_each_row_in_diag[i] = num_non_zeros_each_row[lo+i];
941 num_non_zeros_each_row_off_diag[i] = num_non_zeros_each_row[lo+i];
942 // In the on process ("diagonal block") there cannot be more non-zero columns specified than there are rows
943 if (num_non_zeros_each_row_in_diag[i] > local_size)
944 {
945 num_non_zeros_each_row_in_diag[i] = local_size;
946 }
947 }
948
949 MatSetType(mSystemLhsMatrix, MATMPIAIJ);
950 MatSetType(mPreconditionMatrix, MATMPIAIJ);
951 MatMPIAIJSetPreallocation(mSystemLhsMatrix, PETSC_DEFAULT, num_non_zeros_each_row_in_diag, PETSC_DEFAULT, num_non_zeros_each_row_off_diag);
952 MatMPIAIJSetPreallocation(mPreconditionMatrix, PETSC_DEFAULT, num_non_zeros_each_row_in_diag, PETSC_DEFAULT, num_non_zeros_each_row_off_diag);
953 }
954
955 MatSetFromOptions(mSystemLhsMatrix);
956 MatSetFromOptions(mPreconditionMatrix);
957#if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
958 MatSetOption(mSystemLhsMatrix, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
959 MatSetOption(mPreconditionMatrix, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
960#else
961 MatSetOption(mSystemLhsMatrix, MAT_IGNORE_OFF_PROC_ENTRIES);
962 MatSetOption(mPreconditionMatrix, MAT_IGNORE_OFF_PROC_ENTRIES);
963#endif
964
965 //unsigned total_non_zeros = 0;
966 //for (unsigned i=0; i<mNumDofs; i++)
967 //{
968 // total_non_zeros += num_non_zeros_each_row[i];
969 //}
970 //std::cout << total_non_zeros << " versus " << 500*mNumDofs << "\n" << std::flush;
971
972 delete [] num_non_zeros_each_row;
973 }
974}
975#endif // ABSTRACTCONTINUUMMECHANICSSOLVER_HPP_
#define EXCEPTION(message)
std::vector< c_vector< double, DIM > > mSpatialSolution
AbstractTetrahedralMesh< DIM, DIM > & mrQuadMesh
GaussianQuadratureRule< DIM-1 > * mpBoundaryQuadratureRule
AbstractContinuumMechanicsSolver(AbstractTetrahedralMesh< DIM, DIM > &rQuadMesh, ContinuumMechanicsProblemDefinition< DIM > &rProblemDefinition, std::string outputDirectory, CompressibilityType compressibilityType)
void WriteCurrentPressureSolution(int counterToAppend=-1)
void WriteCurrentSpatialSolution(std::string fileName, std::string fileExtension, int counterToAppend=-1)
virtual std::vector< c_vector< double, DIM > > & rGetSpatialSolution()=0
void AddIdentityBlockForDummyPressureVariables(ApplyDirichletBcsType type)
ContinuumMechanicsProblemDefinition< DIM > & mrProblemDefinition
void CreateVtkOutput(std::string spatialSolutionName="Spatial solution")
void ApplyDirichletBoundaryConditions(ApplyDirichletBcsType type, bool symmetricProblem)
virtual unsigned GetNumNodes() const
bool OptionExists(const std::string &rOption)
static CommandLineArguments * Instance()
static void ZeroRowsWithValueOnDiagonal(Mat matrix, std::vector< unsigned > &rRows, double diagonalValue)
static void ZeroRowsAndColumnsWithValueOnDiagonal(Mat matrix, std::vector< unsigned > rowColIndices, double diagonalValue)
static Vec GetMatrixRowDistributed(Mat matrix, unsigned rowIndex)
static void Finalise(Mat matrix)
static void SetElement(Mat matrix, PetscInt row, PetscInt col, double value)
static void Destroy(Vec &rVec)
static bool AmMaster()
static void Barrier(const std::string callerId="")
static bool IsSequential()
static void SetupMat(Mat &rMat, int numRows, int numColumns, unsigned rowPreallocation, int numLocalRows=PETSC_DECIDE, int numLocalColumns=PETSC_DECIDE, bool ignoreOffProcEntries=true, bool newAllocationError=true)
static void AddScaledVector(Vec y, Vec x, double scaleFactor)
static void Finalise(Vec vector)
static void SetElement(Vec vector, PetscInt row, double value)
static void Zero(Vec vector)
void AddPointData(std::string name, std::vector< double > data)
void AddCellData(std::string name, std::vector< double > data)
void WriteFilesUsingMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, bool keepOriginalElementIndexing=true)