1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 
19 #include "itkFEMSolverHyperbolic.h"
20 #include "itkFEMSpatialObjectReader.h"
21 #include "itkFEMLinearSystemWrapperDenseVNL.h"
22 #include "itkFEMLinearSystemWrapperItpack.h"
23 
24 
25 using FEMSolverType = itk::fem::SolverHyperbolic<2>;
26 
27 
28 // Print K - the global stiffness matrix
PrintK(FEMSolverType * S)29 void PrintK(FEMSolverType *S)
30 {
31   itk::fem::LinearSystemWrapper::Pointer lsw = S->GetLinearSystemWrapper();
32 
33   std::cout << std::endl << "k" << "=[";
34   for( unsigned int j = 0; j < lsw->GetSystemOrder(); j++ )
35     {
36     std::cout << " [";
37     for( unsigned int k = 0; k < lsw->GetSystemOrder(); k++ )
38       {
39       std::cout << lsw->GetMatrixValue(j, k);
40       if( (k + 1) < lsw->GetSystemOrder() )
41         {
42         std::cout << ", ";
43         }
44       }
45     if( j < lsw->GetSystemOrder() - 1 )
46       {
47       std::cout << " ]," << std::endl;
48       }
49     else
50       {
51       std::cout << "]";
52       }
53     }
54   std::cout << "];" << std::endl;
55 }
56 
57 // Print F - the global load vector
PrintF(FEMSolverType * S)58 void PrintF(FEMSolverType *S)
59 {
60   itk::fem::LinearSystemWrapper::Pointer lsw = S->GetLinearSystemWrapper();
61 
62   std::cout << std::endl << "f" << "=[";
63   for( unsigned int j = 0; j < lsw->GetSystemOrder(); j++ )
64     {
65     if( j > 0 )
66       {
67       std::cout << ",  ";
68       }
69     std::cout << lsw->GetVectorValue(j);
70     }
71   std::cout << "];" << std::endl;
72 }
73 
PrintNodalCoordinates(FEMSolverType * S)74 void PrintNodalCoordinates(FEMSolverType *S)
75 // Print the nodal coordinates
76 {
77   std::cout << std::endl << "Nodal coordinates: " << std::endl;
78 
79   std::cout << "xyz" << "=[";
80 
81   int numberOfNodes = S->GetInput()->GetNumberOfNodes();
82   for( int i = 0; i < numberOfNodes; i++ )
83     {
84     std::cout << " [";
85     std::cout << S->GetInput()->GetNode(i)->GetCoordinates();
86     std::cout << "]";
87     }
88   std::cout << "];" << std::endl;
89 }
90 
91 
92 // Useful for display purposes - lets you draw each element
93 // individually, instead of just a stream of nodes
PrintElementCoordinates(FEMSolverType * S)94 void PrintElementCoordinates(FEMSolverType *S )
95 {
96   std::cout << std::endl << "Element coordinates: " << std::endl;
97   int ct = 1;
98 
99   const unsigned int invalidID = itk::fem::Element::InvalidDegreeOfFreedomID;
100 
101   int numberOfElements = S->GetInput()->GetNumberOfElements();
102 
103   for(int i = 0; i < numberOfElements; i++ )
104     {
105     std::cout << "e(" << ct << ",:,:)=[";
106 
107     for (unsigned int n=0; n < S->GetInput()->GetElement(i)->GetNumberOfNodes(); n++)
108       {
109       itk::fem::Element::VectorType nc = S->GetInput()->GetElement(i)->GetNodeCoordinates(n);
110 
111       for (unsigned int d=0, dof; ( dof = S->GetInput()->GetElement(i)->GetNode(n)->GetDegreeOfFreedom(d) ) != invalidID; d++)
112         {
113         nc[d] += S->GetSolution( dof );
114         }
115       std::cout << nc << std::endl;
116       }
117     std::cout << "];" << std::endl;
118     ct++;
119   }
120 }
121 
122 // Useful for display purposes - lets you draw each element
123 // individually, instead of just a stream of nodes
PrintSolution(FEMSolverType * S)124 void PrintSolution(FEMSolverType *S )
125 {
126   std::cout << std::endl << "Solution: " << std::endl;
127   const unsigned int invalidID = itk::fem::Element::InvalidDegreeOfFreedomID;
128   int numberOfNodes = S->GetInput()->GetNumberOfNodes();
129 
130   for (int i = 0; i < numberOfNodes; i++ )
131     {
132     std::cout << "Solution Node " << i << ":";
133     for (unsigned int d=0, dof; ( dof = S->GetInput()->GetNode(i)->GetDegreeOfFreedom(d) ) != invalidID; d++)
134       {
135         std::cout << " " << S->GetSolution( dof );
136       }
137       std::cout << std::endl;
138     }
139 }
140 
itkFEMSolverHyperbolicTest(int ac,char * av[])141 int itkFEMSolverHyperbolicTest(int ac, char* av[])
142 {
143 
144   if (ac < 4)
145     {
146     std::cout << "Usage: " << av[0];
147     std::cout << " input-file iterations lsw (0=VNL, 1=Dense VNL, 2=Itpack)";
148     std::cout << std::endl;
149     return EXIT_FAILURE;
150     }
151 
152   itk::FEMFactoryBase::GetFactory()->RegisterDefaultTypes();
153 
154   unsigned int niter = std::stoi ( av[2] );
155   unsigned int w = std::stoi( av[3] );
156   std::vector<double> solution;
157   if (ac > 4)
158     {
159     solution.resize( ac - 4 );
160     for (int i=4;i<ac;i++)
161       {
162       solution[i-4] = std::stod(av[i]);
163       }
164     }
165 
166   using FEMSpatialObjectReaderType = itk::FEMSpatialObjectReader<2>;
167   using FEMSpatialObjectReaderPointer = FEMSpatialObjectReaderType::Pointer;
168   FEMSpatialObjectReaderPointer SpatialReader = FEMSpatialObjectReaderType::New();
169   SpatialReader->SetFileName( av[1] );
170   try
171     {
172     SpatialReader->Update();
173     }
174   catch (::itk::fem::FEMException & e)
175     {
176     std::cout<<"Error reading FEM problem: "<< av[1] <<"!\n";
177     e.Print(std::cout);
178     return EXIT_FAILURE;
179     }
180 
181   using FEMObjectSpatialObjectType = itk::FEMObjectSpatialObject<2>;
182   FEMObjectSpatialObjectType::ChildrenListType* children = SpatialReader->GetGroup()->GetChildren();
183   FEMObjectSpatialObjectType::Pointer femSO =
184     dynamic_cast<FEMObjectSpatialObjectType *>( (*(children->begin() ) ).GetPointer() );
185   if (!femSO)
186     {
187     std::cout << " dynamic_cast [FAILED]" << std::endl;
188     return EXIT_FAILURE;
189     }
190   delete children;
191 
192   femSO->GetFEMObject()->FinalizeMesh();
193 
194   /**
195    * Third, create the FEM solver object and generate the solution
196    */
197 
198   FEMSolverType::Pointer SH = FEMSolverType::New();
199   SH->SetInput( femSO->GetFEMObject() );
200   SH->SetTimeStep( .5 );
201   SH->SetNumberOfIterations( niter );
202 
203   itk::fem::LinearSystemWrapperDenseVNL lsw_dvnl;
204   itk::fem::LinearSystemWrapperItpack   lsw_itpack;
205   itk::fem::LinearSystemWrapperVNL      lsw_vnl;
206 
207   switch (w)
208     {
209     case 0:
210       // VNL
211       std::cout << std::endl << ">>>>>Using LinearSystemWrapperVNL" << std::endl;
212       SH->SetLinearSystemWrapper(&lsw_vnl);
213       break;
214     case 1:
215       // Dense VNL
216       std::cout << std::endl << ">>>>>Using LinearSystemWrapperDenseVNL" << std::endl;
217       SH->SetLinearSystemWrapper(&lsw_dvnl);
218       break;
219     case 2:
220       // IT Pack
221       std::cout << std::endl << ">>>>>Using LinearSystemWrapperItpack" << std::endl;
222       SH->SetLinearSystemWrapper(&lsw_itpack);
223       break;
224     default:
225       // Sparse VNL - default
226       std::cout << std::endl << ">>>>>Using LinearSystemWrapperVNL" << std::endl;
227       SH->SetLinearSystemWrapper(&lsw_vnl);
228       break;
229     }
230 
231   try
232     {
233     SH->Update();
234     }
235   catch (itk::ExceptionObject &err)
236     {
237     std::cerr << "ITK exception detected: "  << err;
238     return EXIT_FAILURE;
239     }
240 
241   PrintK( SH );
242   PrintF( SH );
243   PrintNodalCoordinates( SH );
244   PrintSolution( SH );
245 
246   if (ac > 4)
247     {
248     int numberOfNodes = SH->GetInput()->GetNumberOfNodes();
249     const unsigned int invalidID = itk::fem::Element::InvalidDegreeOfFreedomID;
250     for (int i = 0; i < numberOfNodes; i++ )
251       {
252       for (unsigned int d=0, dof; ( dof = SH->GetInput()->GetNode(i)->GetDegreeOfFreedom(d) ) != invalidID; d++)
253         {
254         double result = SH->GetSolution( dof );
255         if (fabs(result-solution[dof]) > 1.0e-5)
256           {
257           std::cerr << "Error: Solution outside the expected range: "  << result << ", " << dof << std::endl;
258           return EXIT_FAILURE;
259           }
260         }
261       }
262     }
263   return EXIT_SUCCESS;
264 }
265