@@ -316,6 +316,202 @@ void DASolver::setDAObjFuncList()
316
316
}
317
317
}
318
318
319
+ void DASolver ::getForces (Vec fX , Vec fY , Vec fZ , Vec pointList )
320
+ {
321
+ /*
322
+ Description:
323
+ Compute the nodal forces for all of the nodes on the
324
+ fluid-structure-interaction patches.
325
+
326
+ Output:
327
+ forces : a (nPoint x 3) array of forces for all of the nodes
328
+ of the desired patches.
329
+ */
330
+ Info << "Calculating surface forces" << endl ;
331
+ // Zero point force arrays
332
+ VecZeroEntries (fX );
333
+ VecZeroEntries (fY );
334
+ VecZeroEntries (fZ );
335
+
336
+ VecZeroEntries (pointList );
337
+
338
+ #ifndef SolidDASolver
339
+ // Generate patches, point mesh, and point boundary mesh
340
+ const polyBoundaryMesh & patches = meshPtr_ -> boundaryMesh ();
341
+ const pointMesh & pMesh = pointMesh ::New (meshPtr_ ());
342
+ const pointBoundaryMesh & boundaryMesh = pMesh .boundary ();
343
+
344
+ // Find wall patches and sort in alphabetical order
345
+ label nWallPatch = 0 ;
346
+ forAll (patches , patchI )
347
+ {
348
+ if (patches [patchI ].type () == "wall" )
349
+ {
350
+ nWallPatch += 1 ;
351
+ }
352
+ }
353
+ List < word > patchList (nWallPatch );
354
+
355
+ label iWallPatch = 0 ;
356
+ forAll (patches , patchI )
357
+ {
358
+ if (patches [patchI ].type () == "wall" )
359
+ {
360
+ patchList [iWallPatch ] = patches [patchI ].name ();
361
+ iWallPatch += 1 ;
362
+ }
363
+ }
364
+ SortableList < word > patchListSort (patchList );
365
+
366
+ // compute size of point and connectivity arrays
367
+ label nPoints = 0 ;
368
+ forAll (patchListSort , cI )
369
+ {
370
+ // Get number of points in patch
371
+ label patchIPoints = boundaryMesh .findPatchID (patchListSort [cI ]);
372
+ nPoints += boundaryMesh [patchIPoints ].size ();
373
+ }
374
+
375
+ Info << "Total number of points: " << nPoints << endl ;
376
+
377
+ // Initialize surface field for face-centered forces
378
+ volVectorField volumeForceField (
379
+ IOobject (
380
+ "volumeForceField ",
381
+ meshPtr_ -> time ().timeName (),
382
+ meshPtr_ (),
383
+ IOobject ::NO_READ ,
384
+ IOobject ::NO_WRITE ),
385
+ meshPtr_ (),
386
+ dimensionedVector ("surfaceForce ", dimensionSet (1 , 1 , - 2 , 0 , 0 , 0 , 0 ), vector ::zero ),
387
+ fixedValueFvPatchScalarField ::typeName );
388
+
389
+ // this code is pulled from:
390
+ // src/functionObjects/forcces/forces.C
391
+ // modified slightly
392
+ vector force (vector ::zero );
393
+
394
+ const objectRegistry & db = meshPtr_ -> thisDb ();
395
+ const volScalarField & p = db .lookupObject < volScalarField > ("p" );
396
+
397
+ const surfaceVectorField ::Boundary & Sfb = meshPtr_ -> Sf ().boundaryField ();
398
+
399
+ const DATurbulenceModel & daTurb = daModelPtr_ -> getDATurbulenceModel ();
400
+ tmp < volSymmTensorField > tdevRhoReff = daTurb .devRhoReff ();
401
+ const volSymmTensorField ::Boundary & devRhoReffb = tdevRhoReff ().boundaryField ();
402
+
403
+ // iterate over patches and extract boundary surface forces
404
+ forAll (patchListSort , cI )
405
+ {
406
+ // get the patch id label
407
+ label patchI = meshPtr_ -> boundaryMesh ().findPatchID (patchListSort [cI ]);
408
+ // create a shorter handle for the boundary patch
409
+ const fvPatch & patch = meshPtr_ -> boundary ()[patchI ];
410
+ // normal force
411
+ vectorField fN (Sfb [patchI ] * p .boundaryField ()[patchI ]);
412
+ // tangential force
413
+ vectorField fT (Sfb [patchI ] & devRhoReffb [patchI ]);
414
+ // sum them up
415
+ forAll (patch , faceI )
416
+ {
417
+ force .x () = fN [faceI ].x () + fT [faceI ].x ();
418
+ force .y () = fN [faceI ].y () + fT [faceI ].y ();
419
+ force .z () = fN [faceI ].z () + fT [faceI ].z ();
420
+ volumeForceField .boundaryFieldRef ()[patchI ][faceI ] = force ;
421
+ }
422
+ }
423
+ volumeForceField .write ();
424
+
425
+ // The above volumeForceField is face-centered, we need to interpolate it to point-centered
426
+ label pointCounter = 0 ;
427
+ List < label > globalIndex (nPoints , -1 );
428
+
429
+ pointField meshPoints = meshPtr_ -> points ();
430
+
431
+ vector nodeForce (vector ::zero );
432
+
433
+ PetscScalar * vecArrayFX ;
434
+ VecGetArray (fX , & vecArrayFX );
435
+ PetscScalar * vecArrayFY ;
436
+ VecGetArray (fY , & vecArrayFY );
437
+ PetscScalar * vecArrayFZ ;
438
+ VecGetArray (fZ , & vecArrayFZ );
439
+
440
+ PetscScalar * vecArrayPointList ;
441
+ VecGetArray (pointList , & vecArrayPointList );
442
+
443
+ forAll (patchListSort , cI )
444
+ {
445
+ // get the patch id label
446
+ label patchI = meshPtr_ -> boundaryMesh ().findPatchID (patchListSort [cI ]);
447
+
448
+ // Loop over Faces
449
+ forAll (meshPtr_ -> boundaryMesh ()[patchI ], faceI )
450
+ {
451
+ // Get number of points
452
+ const label nPoints = meshPtr_ -> boundaryMesh ()[patchI ][faceI ].size ();
453
+
454
+ // Divide force to nodes
455
+ nodeForce = volumeForceField .boundaryFieldRef ()[patchI ][faceI ] / double (nPoints );
456
+
457
+ forAll (meshPtr_ -> boundaryMesh ()[patchI ][faceI ], pointI )
458
+ {
459
+ // this is the index that corresponds to meshPoints, which contains both volume and surface points
460
+ // so we can't directly reuse this index because we want to have only surface points
461
+ label faceIPointIndexI = meshPtr_ -> boundaryMesh ()[patchI ][faceI ][pointI ];
462
+
463
+ // Loop over globalMapping array to check if this node is already included
464
+ bool found = false;
465
+ label iPoint ;
466
+ for (label i = 0 ; i < pointCounter ; i ++ ){
467
+ if (faceIPointIndexI == globalIndex [i ])
468
+ {
469
+ found = true;
470
+ iPoint = i ;
471
+ break ;
472
+ }
473
+ }
474
+
475
+ // If node is already included, add value to its entry
476
+ PetscScalar val1 , val2 , val3 ;
477
+ assignValueCheckAD (val1 , nodeForce [0 ]);
478
+ assignValueCheckAD (val2 , nodeForce [1 ]);
479
+ assignValueCheckAD (val3 , nodeForce [2 ]);
480
+ if (found ) {
481
+ // Add Force
482
+ vecArrayFX [iPoint ] += val1 ;
483
+ vecArrayFY [iPoint ] += val2 ;
484
+ vecArrayFZ [iPoint ] += val3 ;
485
+ }
486
+ // If node is not already included, add it as the newest point and add global index mapping
487
+ else {
488
+ // Add Force
489
+ vecArrayFX [pointCounter ] = val1 ;
490
+ vecArrayFY [pointCounter ] = val2 ;
491
+ vecArrayFZ [pointCounter ] = val3 ;
492
+ // Add to Node Order Array
493
+ vecArrayPointList [pointCounter ] = faceIPointIndexI ;
494
+ // Add to Global - Local Mapping
495
+ globalIndex [pointCounter ] = faceIPointIndexI ;
496
+
497
+ // Increment counter
498
+ pointCounter += 1 ;
499
+ }
500
+ }
501
+ }
502
+ }
503
+ VecRestoreArray (fX , & vecArrayFX );
504
+ VecRestoreArray (fY , & vecArrayFY );
505
+ VecRestoreArray (fZ , & vecArrayFZ );
506
+
507
+ VecRestoreArray (pointList , & vecArrayPointList );
508
+ #endif
509
+
510
+
511
+ Info << "Calculating surface force.... Completed!" << endl ;
512
+ return ;
513
+ }
514
+
319
515
void DASolver ::reduceStateResConLevel (
320
516
const dictionary & maxResConLv4JacPCMat ,
321
517
HashTable < List < List < word >>> & stateResConInfo ) const
0 commit comments