ElmerFoamFSI  2.0
ElmerFoamFSI is fluid-solid interaction simulation application built up from OpenFOAM CFD and Elmer CSM coupled through the IMPACT multiphysics software integration infrastructure.
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Macros Groups Pages
SolverModuleDriverParallel.C
Go to the documentation of this file.
1 #include "com.h"
10 #include "com_devel.hpp"
11 #include <iostream>
12 #include <cstring>
13 #include <cstdlib>
14 #include <stdlib.h>
15 #include <sstream>
16 #include "primitive_utilities.H"
17 #include "SolverAgent.H"
18 #include "InterfaceLayer.H"
20 #include "COMM.H"
21 #include <algorithm>
22 
23 
24 COM_EXTERN_MODULE( ElmerCSCParallel);
25 COM_EXTERN_MODULE(SimOut);
26 
27 
28 namespace COM {
29  // typedef for CommunicatorObject
30  typedef IRAD::Comm::CommunicatorObject CommType;
31 
32  void SolverModuleDriver::usage(char *exec){
33  std::cout << std::endl
34  << "Usage: " << std::endl << std::endl
35  << " " << exec << " [-com-mpi] [-fsi] [-loads] time[0] [time[1] ... time[Final]]"
36  << std::endl
37  << " where at least timeFinal is required. Here is the description of switches :"
38  << std::endl << std::endl
39  << " -com-mpi:" << std::endl
40  << " It is not required to use the -com-mpi flag." << std::endl << std::endl
41  << " -fsi :" << std::endl
42  << " Should be used for fluid-solid interaction (FSI) problems to register" << std::endl
43  << " mesh and solution for each given timestep. A vtk file will be created" << std::endl
44  << " for each timestep containing FSI surface mesh and solution values." << std::endl
45  << " It is assumed that all processes share FSI boundaries." << std::endl<<std::endl
46  << " -loads :" << std::endl
47  << " Should be used to change loads during simulaiton" << std::endl<< std::endl
48  << " time[i], i>0:" << std::endl
49  << " At least one timestep should be given. For steady state problem a timestep" << std::endl
50  << " of 1.0 is enough. Values given should increase monotonically." << std::endl;
51  std::exit(1);
52  }
53 
54  int SolverModuleDriver::init(int argc, char *argv[]){
55  std::cout << "SoverModuleDriver: running initializer ... " << std::endl;
56  // processing command-line flags
57  std::string arg;
58  double tmpTime;
59  if(argc > 1){
60  for(int i=1; i < argc; i++){
61  ss.clear();
62  ss.str("");
63  ss << argv[i];
64  if(ss.str() == "-com-mpi")
65  continue;
66  if(ss.str() == "-fsi"){
67  isFSI = true;
68  continue;
69  }
70  if(ss.str() == "-loads"){
71  changeLoads = true;
72  continue;
73  }
74  for(int j=0; j<ss.str().size(); j++){
75  if(!isdigit(ss.str()[j]) && ss.str()[j] != 'e'
76  && ss.str()[j] != 'E' && ss.str()[j] != '-'
77  && ss.str()[j] != '.')
78  usage(argv[0]);
79  }
80  ss >> tmpTime;
81  tNext.push_back(tmpTime);
82  }
83  }
84  else
85  usage(argv[0]);
86 
87  for(int i=1; i < tNext.size(); i++){
88  if(tNext[i] <= tNext[i-1]){
89  usage(argv[0]);
90  exit(1);
91  }
92  }
93 
94  // loading ElmerParallel module
95  COM_LOAD_MODULE_STATIC_DYNAMIC(ElmerCSCParallel, "ELMModule");
96 
97  // loading SimOut on all processes
98  COM_LOAD_MODULE_STATIC_DYNAMIC( SimOUT, "OUT");
99 
100  // check the communicator that the window was loaded on
101  MPI_Comm comm_check;
102  outfile << "Checking ELMModule" << std::endl;
103  outfile << "comm_check = " << comm_check << std::endl;
104  COM_get_communicator("ELMModule", &comm_check);
105  if(comm_check == Comm)
106  outfile << "comm_check == Comm!" << std::endl;
107  else if(comm_check == MPI_COMM_WORLD)
108  outfile << "comm_check == MPI_COMM_WORLD!" << std::endl;
109  else if(comm_check == MPI_COMM_SELF)
110  outfile << "comm_check == MPI_COMM_SELF!" << std::endl;
111  else
112  outfile << "comm_check == None!" << std::endl;
113 
114  // calling module initializer
115  if(color == 0){
117  int init_handle = COM_get_function_handle("ELMModule.Initialize");
118  bool init_func = (init_handle > 0);
119  int verb=1;
120  runs = 0;
121  if(init_func)
122  COM_call_function(init_handle, &runs, &verb);
123  }
124 
125  // FSI problems will register mesh data, accessing them
126  if(isFSI){
127  char getDataItemLoc;
128  COM_Type getDataItemType;
129  std::string getDataItemUnits;
130  // getting node coordinates
131  COM_get_array("ELMModule.nc", myPaneId, &Coord);
132  // check for expected number of nodes
133  COM_get_size("ELMModule.nc", myPaneId, &nNodes);
134  // get connectivity tables for paneIds
135  // :q4: is quad element
136  std::string stringNames;
137  COM_get_connectivities("ELMModule", myPaneId, &nConn, stringNames);
138  std::istringstream ConnISS(stringNames);
139  std::vector<std::string> connNames;
140  for (int i=0; i<nConn; ++i) {
141  std::string name;
142  ConnISS >> name;
143  connNames.push_back(name);
144  std::cout << "Rank #" << myRank
145  << ", ELMModuleDriver:main: Connectivity Table # " << i+1 << ": " << name << std::endl;
146  }
147  // number of nodes per element
148  std::string fullConnName("ELMModule."+connNames[0]);
149  COM_get_dataitem(fullConnName, &getDataItemLoc, &getDataItemType,
150  &nElemNodes, &getDataItemUnits);
151  std::cout << "Rank #" << myRank
152  << ", ELMModuleDriver:main: getDataItemLoc " << getDataItemLoc << std::endl;
153  std::cout << "Rank #" << myRank
154  << ", ELMModuleDriver:main: getDataItemType " << getDataItemType << std::endl;
155  std::cout << "Rank #" << myRank
156  << ", ELMModuleDriver:main: nElemNodes " << nElemNodes << std::endl;
157  std::cout << "Rank #" << myRank
158  << ", ELMModuleDriver:main: getDataItemUnits " << getDataItemUnits << std::endl;
159  // get connectivities
160  COM_get_array(fullConnName.c_str(), myPaneId, &Conn);
161  COM_get_size(fullConnName, myPaneId, &nElem);
162  }
163 
164  return 0;
165  }
166 
168  //If we want to prescribe loads here's where we do it
169 
170  /*
171  // set FSI loads for the structures solver
172  std::cout << "isFSI = " << isFSI << std::endl;
173  if(isFSI && changeLoads){
174  std::cout << "Rank #" << myRank
175  << ", Applying loads ... " << std::endl;
176  COM_get_array("ELMModule.Loads", myPaneId, &Loads);
177  if(Loads){
178  // Get the FSI load size from the structures solver
179  COM_get_size("ELMModule.Loads", myPaneId, &nLoads);
180  std::cout << "Load size = " << nLoads << std::endl;
181  std::cout << "SoverModuleDriver:run: Checking loads" << std::endl;
182  for(int i=0; i < nLoads; i++){
183  for(int j=0; j < 3; j++){
184  Loads[i*3 + j] = double(i*3 + j);
185  std::cout << Loads[i*3+j] << " ";
186  }
187  std::cout << std::endl;
188  }
189  }
190  }
191  std::cout << "Rank #" << myRank
192  << ", Finished applying loads." << std::endl;
193  */
194 
196  int run_handle = COM_get_function_handle("ELMModule.Run");
197  bool run_func = (run_handle > 0);
198  runs = 0;
199  if(run_func){
200  int timestep = 0;
201  for(int i=0; i < tNext.size(); i++){
202  // call run function
203  std::cout << "SoverModuleDriver:run: Calling run function from driver" << std::endl;
204  COM_call_function(run_handle,&runs,&tNext[i]);
205  // dump solution to vtk
206  vtkDump(tNext[i]);
207  // update time
208  timestep++;
209  }
210  }
211  return 0;
212  }
213 
215  // only for FSI problems
216  if (!isFSI)
217  return(0);
218  char getDataItemLoc;
219  COM_Type getDataItemType;
220  std::string getDataItemUnits;
221  // get displacements
222  std::string name;
223  int myDataItemType;
224  name = "ELMModule.Displacements";
225  COM_get_dataitem(name, &getDataItemLoc, &getDataItemType,
226  &nDisp, &getDataItemUnits);
227  std::cout << "Rank #" << myRank
228  << ", ELMModuleDriver:main: Displacement Get DataItem"
229  << std::endl;
230  std::cout << "Rank #" << myRank
231  << ", ELMModuleDriver:main: getDataItemLoc: " << getDataItemLoc << std::endl;
232  std::cout << "Rank #" << myRank
233  << ", ELMModuleDriver:main: getDataItemType: " << getDataItemType << std::endl;
234  std::cout << "Rank #" << myRank
235  << ", ELMModuleDriver:main: arrayLength: " << nDisp << std::endl;
236  std::cout << "Rank #" << myRank
237  << ", ELMModuleDriver:main: getDataItemUnits: " << getDataItemUnits << std::endl;
238  // translate element (e) to cell (c)
239  char myDataItemLoc;
240  if (getDataItemLoc == 'e' || getDataItemLoc == 'E') {
241  locDisp = 'c';
242  } else if (getDataItemLoc == 'n' || getDataItemLoc == 'N') {
243  locDisp = 'n';
244  } else {
245  std::cout << "ELMModuleDriver:main: Unknown Data Item Location" << std::endl;
246  exit(1);
247  }
248  if (getDataItemType == COM_DOUBLE_PRECISION) {
249  typeDisp = 8;
250  } else {
251  std::cout << "ELMModuleDriver:main: Unknown Data Item Type" << std::endl;
252  exit(1);
253  }
254  // acquire dataitem from COM
255  COM_get_array("ELMModule.Displacements", myPaneId, &Disp);
256  // get loads
257  name = "ELMModule.Loads";
258  COM_get_dataitem(name, &getDataItemLoc, &getDataItemType,
259  &nLoads, &getDataItemUnits);
260  std::cout << "Rank #" << myRank
261  << ", ELMModuleDriver:main: Load Get DataItem"
262  << std::endl;
263  std::cout << "Rank #" << myRank
264  << ", ELMModuleDriver:main: getDataItemLoc: " << getDataItemLoc << std::endl;
265  std::cout << "Rank #" << myRank
266  << ", ELMModuleDriver:main: getDataItemType: " << getDataItemType << std::endl;
267  std::cout << "Rank #" << myRank
268  << ", ELMModuleDriver:main: arrayLength: " << nLoads << std::endl;
269  std::cout << "Rank #" << myRank
270  << ", ELMModuleDriver:main: getDataItemUnits: " << getDataItemUnits << std::endl;
271  // translate element (e) to cell (c)
272  if (getDataItemLoc == 'e' || getDataItemLoc == 'E') {
273  locLoads = 'c';
274  } else if (getDataItemLoc == 'n' || getDataItemLoc == 'N') {
275  locLoads = 'n';
276  } else {
277  std::cout << "ELMModuleDriver:main: Unknown Data Item Location" << std::endl;
278  exit(1);
279  }
280  if (getDataItemType == COM_DOUBLE_PRECISION) {
281  typeLoads = 8;
282  } else {
283  std::cout << "ELMModuleDriver:main: Unknown Data Item Type" << std::endl;
284  exit(1);
285  }
286  // acquire dataitem from COM
287  COM_get_array("ELMModule.Loads", myPaneId, &Loads);
288  // get pressures
289  name = "ELMModule.Pressures";
290  COM_get_dataitem(name, &getDataItemLoc, &getDataItemType,
291  &nPress, &getDataItemUnits);
292  std::cout << "Rank #" << myRank
293  << ", ELMModuleDriver:main: Pressures Get DataItem"
294  << std::endl;
295  std::cout << "Rank #" << myRank
296  << ", ELMModuleDriver:main: getDataItemLoc: " << getDataItemLoc << std::endl;
297  std::cout << "Rank #" << myRank
298  << ", ELMModuleDriver:main: getDataItemType: " << getDataItemType << std::endl;
299  std::cout << "Rank #" << myRank
300  << ", ELMModuleDriver:main: arrayLength: " << nPress << std::endl;
301  std::cout << "Rank #" << myRank
302  << ", ELMModuleDriver:main: getDataItemUnits: " << getDataItemUnits << std::endl;
303  // translate element (e) to cell (c)
304  if (getDataItemLoc == 'e' || getDataItemLoc == 'E') {
305  locPress = 'c';
306  } else {
307  std::cout << "ELMModuleDriver:main: Unknown Data Item Location" << std::endl;
308  exit(1);
309  }
310  if (getDataItemType == COM_DOUBLE_PRECISION) {
311  typePress = 8;
312  } else {
313  std::cout << "ELMModuleDriver:main: Unknown Data Item Type" << std::endl;
314  exit(1);
315  }
316  COM_get_array(name.c_str(), myPaneId, &Press);
317 
318  }
319 
320 
322  if(color == 0){
324  int final_handle = COM_get_function_handle("ELMModule.Finalize");
325  bool final_func = (final_handle > 0);
326  runs = 0;
327  if(final_func){
328  COM_call_function(final_handle,&runs);
329  }
330  }
331  COM_UNLOAD_MODULE_STATIC_DYNAMIC( ElmerCSCParallel, "ELMModule");
332  COM_UNLOAD_MODULE_STATIC_DYNAMIC(SimOUT, "OUT");
333  return 0;
334 
335  }
336 
337  int SolverModuleDriver::vtkDump(double timeMark){
338  // only for FSI problems
339  if (!isFSI)
340  return(0);
341  char getDataItemLoc;
342  COM_Type getDataItemType;
343  std::string getDataItemUnits;
344  // creating solverAgent if not yet
345  if (!myAgentIsInit) {
346  myAgentIsInit = true;
347  // put elements into a vector so we can build the solver agent
348  std::vector<unsigned int> connVector;
349  for (int i=0; i<nElem; ++i) {
350  for (int j=0; j<nElemNodes; ++j) {
351  connVector.push_back((Conn[i*nElemNodes+j]));
352  }
353  }
354  // make a solverAgent to store our data
355  myAgent.Solution().Meta().AddField("time", 's', 1, 8, "s");
356  myAgent.Solution().Meta().AddField("endTime", 's', 1, 8, "s");
357  myAgent.Mesh().nc.init(nNodes, Coord);
358  myAgent.Mesh().con.AddElements(nElem, nElemNodes, connVector);
359  }
360  // updating datastructures
361  updateSolution();
362  // displacements
363  myAgent.Solution().Meta().AddField("Displacement", locDisp, nDisp,
364  typeDisp, "");
365  // loads
366  myAgent.Solution().Meta().AddField("Load", locLoads, nLoads,
367  typeLoads, "");
368  // get pressures
369  myAgent.Solution().Meta().AddField("Pressure", locPress, nPress,
370  typePress, "");
371  // create buffers for the actual data
372  myAgent.CreateSoln();
373  unsigned int nnodes = myAgent.Mesh().nc.NNodes();
374  unsigned int nelem = myAgent.Mesh().con.Nelem();
375  // reset the buffers to be our own local buffers
376  myAgent.Solution().SetFieldBuffer("Displacement", Disp);
377  myAgent.Solution().SetFieldBuffer("Load", Loads);
378  myAgent.Solution().SetFieldBuffer("Pressure", Press);
379  // write initial mesh data out to a VTK file
380  std::ofstream Ouf;
381  ss.clear();
382  ss.str("");
383  ss << timeMark
384  << "_proc_"
385  << myRank;
386  std::string filename;
387  filename = "fsi_" + ss.str() +".vtk";
388  Ouf.open(filename.c_str());
389  if(!Ouf){
390  std::cerr << "ELMModuleDriver:main: DumpSolution: Error: Could not open output file, "
391  << filename << "." << std::endl;
392  return -1;
393  }
394  std::cout << "Rank #" << myRank
395  << ", ELMModuleDriver:main: WriteVTKToStream for " << timeMark << std::endl;
396  SolverUtils::WriteVTKToStream("ELMModule", myAgent, Ouf);
397  Ouf.close();
398  }
399 
400  int parallelProgram(int argc, char *argv[]){
401  int parErr;
402  // instantiating IRAD's communicatorObject
403  // this constructor calls MPI_init internally and
404  // sets up everthing with MPI
405  std::cout <<"ElmerModuleDriver:Main: Setting up parallel communicator..." << std::endl;
406  CommType communicator(&argc,&argv);
407  MPI_Comm masterComm = communicator.GetCommunicator();
408  int rank = communicator.Rank();
409  int nproc = communicator.Size();
410  int color = 0;
411  std::cout << "ElmerModuleDriver:Main:Rank #"
412  << rank
413  << ", I see "
414  << nproc
415  << " proccesses."
416  << std::endl;
417  // initializing COM
418  COM_init( &argc, &argv);
419 
420  // instantiating solver driver object
421  SolverModuleDriver driverObject;
422  driverObject.setRank(rank);
423  driverObject.myPaneId=100+rank;
424 
425  // checking streamer process
426  if (driverObject.isStreamer())
427  std::cout << "Hi, I am a streamer ..." << std::endl;
428 
429  // setting up output files for parallel debugging
430  std::string outfile_name;
431  std::stringstream ss;
432  std::string str_rank;
433  ss << rank;
434  ss >> str_rank;
435  outfile_name = "out" + str_rank + ".dat";
436  driverObject.outfile.open(outfile_name.c_str());
437 
438  // setting color for the driver object
439  driverObject.setColor(color);
440  driverObject.outfile << "color = " << color << std::endl;
441  driverObject.outfile << "rank = " << rank << std::endl;
442  CommType newCommunicator;
443  communicator.Split(color, rank, newCommunicator);
444  driverObject.outfile << "communicator.Size() = " << communicator.Size() << std::endl;
445  driverObject.outfile << "newCommunicator.Size() = " << newCommunicator.Size() << std::endl;
446  driverObject.setComm(newCommunicator.GetCommunicator());
447  MPI_Comm newComm;
448  newComm = newCommunicator.GetCommunicator();
449  COM_set_default_communicator(newComm);
450 
451  // calling initializer, for FSI problems mesh and solution
452  // related datastructures will be automatically registered
453  driverObject.init(argc, argv);
454 
455  // get information about what was registered in this window
456  int numDataItems=0;
457  std::string output;
458  COM_get_dataitems("ELMModule", &numDataItems, output);
459  std::istringstream Istr(output);
460  std::vector<std::string> dataItemNames;
461  for (int i=0; i<numDataItems; ++i) {
462  std::string name;
463  Istr >> name;
464  dataItemNames.push_back(name);
465  std::cout << "Rank #" << rank
466  << ", ElmerModuleDriver:main: DataItem # " << i << ": " << name << std::endl;
467  }
468  // list of panes for this process: each process creates a single pane
469  // with paneId = 100 + rank
470  int numPanes;
471  int* paneList;
472  COM_get_panes("ELMModule", &numPanes, &paneList);
473  std::cout << "Rank #" << rank
474  << ", ELMModuleDriver:main: Number of Panes " << numPanes << std::endl;
475  for (int i=0; i<numPanes; ++i)
476  std::cout << "Rank #" << rank
477  << ", ELMModuleDriver:main: Pane ID # " << i+1 << "=" << paneList[i] << std::endl;
478 
479  // updating solution
480  driverObject.updateSolution();
481 
482  // dumping intial conditions to vtk
483  //if (driverObject.isFSISim())
484  // driverObject.vtkDump(0);
485 
486  // scattering FSI loads to the structures solver processes
487  // only for FSI problesm
488  if(driverObject.isFSISim() && driverObject.isChangeLoad()){
489  std::vector<int> nLoadsVec;
490  std::vector<int> nLoadsTotVec;
491  std::vector<int> nRecvAllVec;
492  nLoadsVec.push_back(driverObject.nNodes*driverObject.nLoads);
493  std::cout << "Rank #"<<rank
494  <<", nLoadsVec["<<rank<<"] = "<<nLoadsVec[rank]<<std::endl;
495  parErr = newCommunicator.Gatherv(nLoadsVec, nLoadsTotVec, nRecvAllVec);
496  if (parErr)
497  std::cout << "Error in gathering information from processes." << std::endl;
498  if (rank == 0){
499  for (int iProc=0; iProc<nLoadsTotVec.size(); iProc++)
500  std::cout << "Rank #"<<rank
501  <<", nLoadsTotVec["<<iProc<<"] = "<<nLoadsTotVec[iProc]<<std::endl;
502  }
503  // defining new loads
504  std::vector<double> loadsVec;
505  std::vector<double> loadsTotVec;
506  int nLoadsTot = 0;
507  if (rank == 0){
508  for (int iProc=0; iProc < nLoadsTotVec.size(); iProc++){
509  nLoadsTot += nLoadsTotVec[iProc];
510  }
511  loadsTotVec.resize(nLoadsTot,0.0);
512  for (int iLoad=1; iLoad < nLoadsTot; iLoad+=3)
513  loadsTotVec[iLoad] = 1.0;
514  std::cout << "Size of loadsTotVec = " << loadsTotVec.size() << std::endl;
515  }
516  // parallel scattering
517  parErr = newCommunicator.Scatterv(loadsTotVec, nLoadsTotVec, loadsVec);
518  if (parErr)
519  std::cout << "Error in scattering information to processes." << std::endl;
520  std::cout << "Rank #" << rank
521  << ", number of load components I received = " << loadsVec.size()
522  << std::endl;
523  // applying loads for each process
524  for (int iLoad=0; iLoad<(driverObject.nLoads*driverObject.nNodes); ++iLoad){
525  driverObject.Loads[iLoad] = loadsVec[iLoad];
526  std::cout << "Rank #" << rank
527  << ", driverObject.Loads ["<<iLoad<<"] = "
528  << driverObject.Loads[iLoad] << std::endl;
529  }
530  // setting a barrier here
531  std::cout << "Rank #"<<rank<<"...Reaching to barrier"<<std::endl;
532  newCommunicator.Barrier();
533  }
534 
535  // calling run step
536  driverObject.run();
537  newCommunicator.Barrier();
538 
539  // gathering all displacements in root
540  // only for FSI problesm
541  if(driverObject.isFSISim() && driverObject.isChangeLoad()){
542  std::vector<double> dispVec;
543  std::vector<double> dispTotVec;
544  std::vector<int> nSendAllVec;
545  for (int iDisp=0; iDisp<(driverObject.nDisp*driverObject.nNodes); ++iDisp){
546  dispVec.push_back(driverObject.Disp[iDisp]);
547  std::cout << "Rank #" << rank
548  << ", dispVec ["<<iDisp<<"] = " << dispVec[iDisp] << std::endl;
549  }
550  std::cout << "Rank #" << rank
551  << ", dispVec size = " << dispVec.size() << std::endl;
552  // parallel gathering
553  parErr = newCommunicator.Gatherv(dispVec, dispTotVec, nSendAllVec);
554  if (parErr)
555  std::cout << "Error in gathering information from processes." << std::endl;
556  std::cout << "Rank #" << rank
557  << ", size of dispTotVec = " << dispTotVec.size()
558  << std::endl;
559  // setting a barrier here
560  std::cout << "Rank #"<<rank<<"...Reaching to barrier"<<std::endl;
561  newCommunicator.Barrier();
562  // checking gather data vector
563  if (rank == 0){
564  double maxDisp = 0.0;
565  double minDisp = 0.0;
566  for (int iDisp=0; iDisp<dispTotVec.size(); iDisp++){
567  maxDisp = std::max(dispTotVec[iDisp], maxDisp);
568  minDisp = std::min(dispTotVec[iDisp], minDisp);
569  std::cout << "Rank #0, dispTotVec [" << iDisp << "] = "
570  << dispTotVec[iDisp] << std::endl;
571  }
572  outfile_name = "maxMinDisp.dat";
573  std::ofstream testFile;
574  testFile.open(outfile_name.c_str());
575  testFile << maxDisp << std::endl << minDisp << std::endl;
576  testFile.close();
577  }
578  // writing window to HDF
579  int OUT_set = COM_get_function_handle( "OUT.set_option");
580  int OUT_write = COM_get_function_handle( "OUT.write_dataitem");
581  const char *win_out= "ELMModule";
582  std::string win_out_pre(win_out);
583  win_out_pre.append(".");
584  int OUT_all = COM_get_dataitem_handle((win_out_pre+"all").c_str());
585  ss.clear();
586  ss.str("");
587  ss << "_proc_"
588  << rank;
589  std::string fileOut;
590  fileOut = "ELMModule_window" + ss.str();
591  COM_call_function( OUT_set, "format", "HDF4");
592  COM_call_function( OUT_write, (fileOut + ".hdf").c_str(), &OUT_all, win_out,
593  "0000");
594  }
595 
596  // calling finalize
597  driverObject.finalize();
598 
599  // closing log file for the driver object
600  driverObject.outfile.close();
601 
602  // finalize comm
603  COM_finalize();
604 
605  // finalizing communicator
606  communicator.Finalize();
607  return 0;
608  }
609 }
610 
611 int main(int argc, char** argv) {
612  //std::cout << "Calling parallelProgram ... " << std::endl;
613  return(COM::parallelProgram(argc, argv));
614 }
615 
int parallelProgram(int argc, char *argv[])
IRAD::Comm::CommunicatorObject CommType
int init(int argc, char *argv[])
void setComm(MPI_Comm newComm)
COM_EXTERN_MODULE(OpenFoamFSI)
#define main
Definition: icoFoamModule.C:2