MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
AcaSolver< nDim > Class Template Reference

Acoustic extrapolation of near/near-far field data to the true far-field using an integral method (currently only FWH, but should allow for other methods to be implemented as well) More...

#include <acasolver.h>

Inheritance diagram for AcaSolver< nDim >:
[legend]
Collaboration diagram for AcaSolver< nDim >:
[legend]

Classes

struct  AcaSymBc
 Hold data for symmetry boundary condition. More...
 
struct  ConversionFactors
 Conversion-Factors for the input conversion. More...
 
struct  FOURIER
 
struct  FWH
 
struct  FWH_APE
 
struct  FWH_TIME
 
struct  PP
 
struct  WINDOW
 

Public Member Functions

 AcaSolver (const MInt solverId, const MPI_Comm comm)
 
 ~AcaSolver () override
 
MBool solutionStep () override
 Main compute method to perform acoustic far-field prediction. More...
 
MBool solverConverged ()
 
MBool isActive () const override
 
void initSolver () override
 Initialize solver. More...
 
void finalizeInitSolver () override
 
MFloat time () const override
 Return the time. More...
 
MInt noVariables () const override
 Return the number of variables. More...
 
MInt noInternalCells () const override
 Return the number of internal cells within this solver. More...
 
void preTimeStep () override
 
void postTimeStep ()
 
virtual void saveSolverSolution (const MBool, const MBool)
 
virtual void cleanUp ()
 
- Public Member Functions inherited from Solver
MString getIdentifier (const MBool useSolverId=false, const MString preString="", const MString postString="_")
 
virtual ~Solver ()=default
 
virtual MInt noInternalCells () const =0
 Return the number of internal cells within this solver. More...
 
virtual MFloat time () const =0
 Return the time. More...
 
virtual MInt noVariables () const
 Return the number of variables. More...
 
virtual void getDimensionalizationParams (std::vector< std::pair< MFloat, MString > > &) const
 Return the dimensionalization parameters of this solver. More...
 
void updateDomainInfo (const MInt domainId, const MInt noDomains, const MPI_Comm mpiComm, const MString &loc)
 Set new domain information. More...
 
virtual MFloata_slope (const MInt, MInt const, const MInt)
 
virtual MBool a_isBndryCell (const MInt) const
 
virtual MFloata_FcellVolume (MInt)
 
virtual MInt getCurrentTimeStep () const
 
virtual void accessSampleVariables (MInt, MFloat *&)
 
virtual void getSampleVariableNames (std::vector< MString > &NotUsed(varNames))
 
virtual MBool a_isBndryGhostCell (MInt) const
 
virtual void saveCoarseSolution ()
 
virtual void getSolverSamplingProperties (std::vector< MInt > &NotUsed(samplingVarIds), std::vector< MInt > &NotUsed(noSamplingVars), std::vector< std::vector< MString > > &NotUsed(samplingVarNames), const MString NotUsed(featureName)="")
 
virtual void initSolverSamplingVariables (const std::vector< MInt > &NotUsed(varIds), const std::vector< MInt > &NotUsed(noSamplingVars))
 
virtual void calcSamplingVariables (const std::vector< MInt > &NotUsed(varIds), const MBool NotUsed(exchange))
 
virtual void calcSamplingVarAtPoint (const MFloat *NotUsed(point), const MInt NotUsed(id), const MInt NotUsed(sampleVarId), MFloat *NotUsed(state), const MBool NotUsed(interpolate)=false)
 
virtual void balance (const MInt *const NotUsed(noCellsToReceiveByDomain), const MInt *const NotUsed(noCellsToSendByDomain), const MInt *const NotUsed(targetDomainsByCell), const MInt NotUsed(oldNoCells))
 Perform load balancing. More...
 
virtual MBool hasSplitBalancing () const
 Return if load balancing for solver is split into multiple methods or implemented in balance() More...
 
virtual void balancePre ()
 
virtual void balancePost ()
 
virtual void finalizeBalance ()
 
virtual void resetSolver ()
 Reset the solver/solver for load balancing. More...
 
virtual void cancelMpiRequests ()
 Cancel open mpi (receive) requests in the solver (e.g. due to interleaved execution) More...
 
virtual void setCellWeights (MFloat *)
 Set cell weights. More...
 
virtual MInt noLoadTypes () const
 
virtual void getDefaultWeights (MFloat *NotUsed(weights), std::vector< MString > &NotUsed(names)) const
 
virtual void getLoadQuantities (MInt *const NotUsed(loadQuantities)) const
 
virtual MFloat getCellLoad (const MInt NotUsed(cellId), const MFloat *const NotUsed(weights)) const
 
virtual void limitWeights (MFloat *NotUsed(weights))
 
virtual void localToGlobalIds ()
 
virtual void globalToLocalIds ()
 
virtual MInt noCellDataDlb () const
 Methods to inquire solver data information. More...
 
virtual MInt cellDataTypeDlb (const MInt NotUsed(dataId)) const
 
virtual MInt cellDataSizeDlb (const MInt NotUsed(dataId), const MInt NotUsed(cellId))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MInt *const NotUsed(data))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MLong *const NotUsed(data))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MFloat *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MInt *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MLong *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MFloat *const NotUsed(data))
 
virtual void getGlobalSolverVars (std::vector< MFloat > &NotUsed(globalFloatVars), std::vector< MInt > &NotUsed(globalIntVars))
 
virtual void setGlobalSolverVars (std::vector< MFloat > &NotUsed(globalFloatVars), std::vector< MInt > &NotUsed(globalIdVars))
 
void enableDlbTimers ()
 
void reEnableDlbTimers ()
 
void disableDlbTimers ()
 
MBool dlbTimersEnabled ()
 
void startLoadTimer (const MString name)
 
void stopLoadTimer (const MString &name)
 
void stopIdleTimer (const MString &name)
 
void startIdleTimer (const MString &name)
 
MBool isLoadTimerRunning ()
 
virtual MInt noSolverTimers (const MBool NotUsed(allTimings))
 
virtual void getSolverTimings (std::vector< std::pair< MString, MFloat > > &NotUsed(solverTimings), const MBool NotUsed(allTimings))
 
virtual void getDomainDecompositionInformation (std::vector< std::pair< MString, MInt > > &NotUsed(domainInfo))
 
void setDlbTimer (const MInt timerId)
 
virtual void prepareAdaptation (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &)
 
virtual void reinitAfterAdaptation ()
 
virtual void prepareAdaptation ()
 prepare adaptation for split adaptation before the adaptation loop More...
 
virtual void setSensors (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &)
 set solver sensors for split adaptation within the adaptation loop More...
 
virtual void saveSensorData (const std::vector< std::vector< MFloat > > &, const MInt &, const MString &, const MInt *const)
 
virtual void postAdaptation ()
 post adaptation for split adaptation within the adaptation loop More...
 
virtual void finalizeAdaptation ()
 finalize adaptation for split sadptation after the adaptation loop More...
 
virtual void refineCell (const MInt)
 Refine the given cell. More...
 
virtual void removeChilds (const MInt)
 Coarsen the given cell. More...
 
virtual void removeCell (const MInt)
 Remove the given cell. More...
 
virtual void swapCells (const MInt, const MInt)
 Swap the given cells. More...
 
virtual void swapProxy (const MInt, const MInt)
 Swap the given cells. More...
 
virtual MInt cellOutside (const MFloat *, const MInt, const MInt)
 Check whether cell is outside the fluid domain. More...
 
virtual void resizeGridMap ()
 Swap the given cells. More...
 
virtual MBool prepareRestart (MBool, MBool &)
 Prepare the solvers for a grid-restart. More...
 
virtual void reIntAfterRestart (MBool)
 
MPI_Comm mpiComm () const
 Return the MPI communicator used by this solver. More...
 
virtual MInt domainId () const
 Return the domainId (rank) More...
 
virtual MInt noDomains () const
 
virtual MBool isActive () const
 
void setSolverStatus (const MBool status)
 
MBool getSolverStatus ()
 Get the solver status indicating if the solver is currently active in the execution recipe. More...
 
MString testcaseDir () const
 Return the testcase directory. More...
 
MString outputDir () const
 Return the directory for output files. More...
 
MString restartDir () const
 Return the directory for restart files. More...
 
MString solverMethod () const
 Return the solverMethod of this solver. More...
 
MString solverType () const
 Return the solverType of this solver. More...
 
MInt restartInterval () const
 Return the restart interval of this solver. More...
 
MInt restartTimeStep () const
 Return the restart interval of this solver. More...
 
MInt solverId () const
 Return the solverId. More...
 
MBool restartFile ()
 
MInt readSolverSamplingVarNames (std::vector< MString > &varNames, const MString featureName="") const
 Read sampling variables names, store in vector and return the number of sampling variables. More...
 
virtual MBool hasRestartTimeStep () const
 
virtual MBool forceAdaptation ()
 
virtual void preTimeStep ()=0
 
virtual void postTimeStep ()=0
 
virtual void initSolver ()=0
 
virtual void finalizeInitSolver ()=0
 
virtual void saveSolverSolution (const MBool NotUsed(forceOutput)=false, const MBool NotUsed(finalTimeStep)=false)=0
 
virtual void cleanUp ()=0
 
virtual MBool solutionStep ()
 
virtual void preSolutionStep (MInt)
 
virtual MBool postSolutionStep ()
 
virtual MBool solverConverged ()
 
virtual void getInterpolatedVariables (MInt, const MFloat *, MFloat *)
 
virtual void loadRestartFile ()
 
virtual MInt determineRestartTimeStep () const
 
virtual void writeRestartFile (MBool)
 
virtual void writeRestartFile (const MBool, const MBool, const MString, MInt *)
 
virtual void setTimeStep ()
 
virtual void implicitTimeStep ()
 
virtual void prepareNextTimeStep ()
 

Private Types

enum  NONDIMBASIS { NONDIMACA = 0 , NONDIMSTAGNATION = 1 , NONDIMLB = 2 }
 
using SurfaceDataCollector = maia::acoustic_analogy::collector::SurfaceDataCollector< nDim >
 
using ObserverDataCollector = maia::acoustic_analogy::observer_collector::ObserverDataCollector< nDim >
 
using SourceParameters = maia::acoustic::SourceParameters
 
using SourceVars = maia::acoustic::SourceVars
 
using Timers = maia::acoustic::Timers_
 

Private Member Functions

void initTimers ()
 Initialize solver timers. More...
 
void averageTimer ()
 Average all FWH timer over participating ranks. More...
 
void setInputOutputProperties ()
 Read/set all I/O related properties. More...
 
void setNumericalProperties ()
 Read/set all numerical properties. More...
 
MInt noSurfaces ()
 Return number of surfaces. More...
 
MBool hasSurface (const MInt surfaceId)
 Return if this rank has data of this surface. More...
 
MInt noSurfaceElements (const MInt surfaceId)
 Return number of (local) surfaces elements for a surface. More...
 
MInt totalNoSurfaceElements ()
 Return total number of (local) surfaces elements. More...
 
MInt localSurfaceOffset (const MInt sId)
 Return local offset of a surface in m_surfaceData. More...
 
MInt noSamples ()
 Return number of samples (i.e. number of time steps) More...
 
MInt noObservers ()
 Return local number of observer points. More...
 
MInt observerOffset ()
 Return local number of observer points. More...
 
MInt globalNoObservers ()
 Return number of observer points. More...
 
MInt a_localObserverId (const MInt globalObserverId)
 Return local observer id. More...
 
MInt a_globalObserverId (const MInt localObserverId)
 Return global observer id. More...
 
MFloat a_globalObserverCoordinate (const MInt globalObserverId, const MInt dir)
 Accessor for global observer coordinates. More...
 
std::array< MFloat, nDim > getGlobalObserverCoordinates (const MInt globalObserverId)
 Accessor for global observer coordinates. More...
 
MInt getObserverDomainId (const MInt globalObserverId)
 Get domain id of (global) observer. More...
 
void initObserverPoints ()
 Initialize observer points. More...
 
void initParallelization ()
 Initialize parallelization (distribution of surface segments on all domains) More...
 
void distributeObservers ()
 Distribute observers on all ranks. More...
 
MString getSurfaceDataFileName (const MInt surfaceId, const MInt fileNo)
 IO methods. More...
 
void readSurfaceData ()
 Read the surface data (or generate for an analytical case) More...
 
void readSurfaceDataFromFile (const MInt surfaceId)
 Read the data for one surface. More...
 
void storeSurfaceData (const MInt surfaceId)
 Store the surface data. Note: used for validating the data input and for the output of generated data. More...
 
void readNoSegmentsAndSamples (const MInt surfaceId, MInt &noSegments, MInt &noSamples, MString &inputFileName)
 Read the number of segments and samples for the given surface id. More...
 
void printMessage (const MString msg)
 Info functions. More...
 
void calcSourceTerms ()
 Main compute functions. More...
 
void calcWindowFactors (MFloat *const p_window)
 Compute the window function factors and the normalization factor. More...
 
void windowAndTransformSources ()
 Apply window function to source terms and transform into frequency domain. More...
 
void windowAndTransformObservers ()
 Apply window function to the observer time series data and transform it into frequency domain. More...
 
void calcFrequencies ()
 Calculate the frequencies. More...
 
void calcSurfaceIntegralsForObserver (const std::array< MFloat, nDim > coord, MFloat *const p_complexVariables)
 Calculate the FWH surface integrals for a certain observer location. More...
 
void calcSurfaceIntegralsAtSourceTime (const MInt globalObserverId)
 Calculate the FWH surface integrals for a certain observer using the time-domain formulation. More...
 
MFloat calcTimeDerivative (const MInt segmentId, const MInt varId, const MInt tau)
 
void interpolateFromSourceToObserverTime (const MFloat distMinObservers, MFloat *const p_perturbedFWH)
 Interpolate the observer pressure signal from source time to observer time using the advanced time approach by Casalino. Reference: Casalino, D., 2003, An advanced time approach ... doi.org/10.1016/s0022-460x(02)00986-0. More...
 
void combineSurfaceIntegrals (const MInt globalObserverId, MFloat *const p_complexVariables)
 Combine the FWH surface integrals of all ranks. More...
 
void combineSurfaceIntegralsInTime (const MInt globalObserverId, MFloat *const p_perturbedFWH)
 Combine the FWH surface integrals of the time domain method of all ranks. More...
 
void calcMinDistanceForObservers (MFloat *const distMinObservers)
 Find the minimum distance from the surface elements to the observers. More...
 
void calculateObserverInFrequency ()
 Calculate the observer signals in frequency domain. More...
 
void calculateObserverInTime ()
 Calculate the observer signals in time domain. More...
 
void backtransformObservers ()
 Backtransform the observer frequency signals into the time domain. More...
 
void saveObserverSignals ()
 Save the observer signals. Save observer data: 1. pressure data in time domain and 2. pressure data in frequency domain. More...
 
void loadObserverSignals ()
 Load the observer signals from a file for further postprocessing. More...
 
void postprocessObserverSignals ()
 Postprocessing of observer signals. More...
 
void FastFourierTransform (MFloat *dataArray, const MInt size, const MInt dir, MFloat *result, const MBool inPlace)
 Functions for Fourier Transformation. More...
 
void DiscreteFourierTransform (MFloat *dataArray, const MInt size, const MInt dir, MFloat *result, const MBool inPlace)
 Discrete Fourier transform (computational expensive O(n^2) instead of O(n*logn) compared to FFT) More...
 
void checkNoSamplesPotencyOfTwo ()
 
void calcSourceTermsFwhFreq (const MInt segmentId)
 Source term compute kernels. More...
 
void calcSourceTermsFwhTime (const MInt segmentId)
 Calculate FWH source terms for the time domain FWH formulation Reference: [1] Brentner, K. S. and F. Farassat, 1998, Analytical Comparison ... doi.org/10.2514/2.558 [2] Casalino, D., 2003, An advanced time approach ... doi.org/10.1016/s0022-460x(02)00986-0 [3] Brès, G., 2010, A Ffowcs Williams - Hawkings ... doi.org/10.2514/6.2010-3711. More...
 
void transformCoordinatesToFlowDirection2D (MFloat *const fX, MFloat *const fY)
 Coordinate transformation. More...
 
void transformCoordinatesToFlowDirection3D (MFloat *const fX, MFloat *const fY, MFloat *const fZ)
 
void transformBackToOriginalCoordinate2D (MFloat *const fX, MFloat *const fY)
 
void transformBackToOriginalCoordinate3D (MFloat *const fX, MFloat *const fY, MFloat *const fZ)
 
void generateSurfaces ()
 Generation of surfaces. More...
 
void generateSurfacePlane (const MInt sId)
 Generate a surface plane (Cartesian). More...
 
void generateSurfaceCircle (const MInt sId)
 Generate a circular surface in 2D. More...
 
MInt readNoSegmentsSurfaceGeneration (const MInt sId, std::vector< MInt > &noSegments, const MInt lengthCheck=-1)
 Determine the number of segments to be generated for a surface, returns the total number of segments and a vector with the number of segments in each direction for the specific surface type. More...
 
void generateSurfaceData ()
 Generation of analytical input data. More...
 
void genMonopoleAnalytic2D (const MFloat *coord, const SourceParameters &param, SourceVars &vars)
 Monopole. More...
 
void genMonopoleAnalytic3D (const MFloat *coord, const SourceParameters &param, SourceVars &vars)
 3D analytic monopole generation More...
 
void genDipoleAnalytic2D (const MFloat *coord, const SourceParameters &param, SourceVars &vars)
 Dipole. More...
 
void genDipoleAnalytic3D (const MFloat *coord, const SourceParameters &param, SourceVars &vars)
 3D dipole analytic More...
 
void genQuadrupoleAnalytic2D (const MFloat *coord, const SourceParameters &param, SourceVars &vars)
 Quadrupole. More...
 
void genQuadrupoleAnalytic3D (const MFloat *coord, const SourceParameters &param, SourceVars &vars)
 3D quadrupole analytic More...
 
void genVortexConvectionAnalytic2D (const MFloat *obsCoord, const SourceParameters &m_sourceParameters, SourceVars &sourceVars)
 Inviscid vortex convection. More...
 
void applySymmetryBc (const std::array< MFloat, nDim > coord, MFloat *const p_complexVariables)
 Symmetry boundary condition. More...
 
void calcObsPressureAnalytic ()
 
void initConversionFactors ()
 Initialize the conversion factors required to convert between. More...
 
void changeDimensionsSurfaceData ()
 Change of the non-dimensionalization of input data from the stagnation state (0) non-dim. to the undisturbed freestream state (inf) non-dim. More...
 
void changeDimensionsObserverData ()
 
void computeDt ()
 
void computeAccuracy ()
 

Private Attributes

std::vector< std::unique_ptr< AcaPostProcessing > > m_post
 
MBool m_isFinished = false
 
MInt m_acaResultsNondimMode = 0
 
struct AcaSolver::ConversionFactors m_input2Aca
 
struct AcaSolver::ConversionFactors m_aca2Output
 
MInt m_noSurfaces = -1
 Number of surfaces. More...
 
std::vector< MIntm_surfaceIds {}
 Ids of the surface input file. More...
 
MBool m_useMergedInputFile
 
MInt m_inputFileIndexStart
 
MInt m_inputFileIndexEnd
 
std::vector< MIntm_noSurfaceElements {}
 Number of (local) surface elements for each surface. More...
 
MBool m_allowMultipleSurfacesPerRank = false
 Allow multiple surfaces per rank. More...
 
std::vector< MIntm_noSurfaceElementsGlobal {}
 Total number of surface elements for each surface. More...
 
std::vector< MIntm_surfaceElementOffsets {}
 Local surface element offsets for each surface. More...
 
std::vector< MPI_Comm > m_mpiCommSurface {}
 Surface local MPI communicators. More...
 
std::vector< MIntm_noDomainsSurface {}
 Surface local number of domains. More...
 
std::vector< MIntm_domainIdSurface {}
 Surface local domain id. More...
 
std::vector< MFloatm_surfaceWeightingFactor {}
 Weighting factor for each surface (for surface averaging) More...
 
std::vector< MStringm_surfaceInputFileName {}
 Surface input file names that were used for sampling. More...
 
MInt m_noSamples = -1
 Number of samples. More...
 
MInt m_totalNoSamples = -1
 Total number of samples in input data files. More...
 
MInt m_sampleStride = 1
 Stride of used samples in input data files. More...
 
MInt m_sampleOffset = 0
 Offset in input data files from which to start reading samples. More...
 
SurfaceDataCollector m_surfaceData
 Collector for surface data. More...
 
MInt m_acousticMethod = -1
 Acoustic extrapolation method to use, see enum ExtrapolationMethods in enums.h. More...
 
MInt m_fwhTimeShiftType = 0
 
MInt m_fwhMeanStateType = 0
 
MInt m_noVariables = -1
 
MInt m_noComplexVariables = -1
 
std::map< MString, MIntm_inputVars {}
 Set of input variables. More...
 
MInt m_windowType = 0
 Window type. More...
 
MFloat m_windowNormFactor = -1.0
 Normalization factor of window. More...
 
MInt m_transformationType = 0
 Fourier type. More...
 
MInt m_noGlobalObservers = -1
 Number of samples. More...
 
std::vector< MFloatm_globalObserverCoordinates
 
ObserverDataCollector m_observerData
 Coordinates of (global) observer points. More...
 
MInt m_offsetObserver = 0
 Collector for (local) observer data. More...
 
MInt m_noObservers = 0
 Offset of local observer. More...
 
std::array< MFloat, nDim *nDim > m_transformationMatrix
 Number of local observer. More...
 
MBool m_zeroFlowAngle = false
 
MString m_inputDir
 I/O. More...
 
MString m_outputFilePrefix = ""
 Input directory. More...
 
MBool m_storeSurfaceData = false
 Prefix for all output files. More...
 
MString m_observerFileName
 File containing observer points. More...
 
MBool m_generateObservers = false
 Enable observer point generation (instead of reading from file) More...
 
MBool m_generateSurfaceData = false
 Enable generation of analytical surface data. More...
 
MInt m_sourceType = -1
 Source Type. More...
 
maia::acoustic::SourceParameters m_sourceParameters
 Parameter vector. More...
 
MFloat m_omega_factor = -1.0
 Omega factor. More...
 
MFloat m_lambdaZero = -1.0
 Wave length lambda. More...
 
MFloat m_lambdaMach = -1.0
 
MFloat m_cInfty = -1.0
 Non-dimensionalization variables. More...
 
MFloat m_rhoInfty = -1.0
 
std::vector< MFloatm_Analyticfreq {}
 Analytic Fourier Transformation, also used for Validation. More...
 
std::vector< MFloatm_rmsP_Analytic {}
 Analytic rms pressure for accuracy function. More...
 
MFloat m_dt = -1.0
 Constant time step size. More...
 
MFloat m_MaVec [3]
 Mach vector. More...
 
MFloat m_Ma = -1.0
 Mach number. More...
 
MFloat m_MaDim = -1.0
 Mach number used for change of nondimensionalization. More...
 
MBool m_FastFourier = false
 Can FFT be used? More...
 
std::vector< MFloatm_times {}
 Storage for times and frequencies. More...
 
std::vector< MFloatm_frequencies {}
 
MBool m_hasTimes = false
 
MInt m_noPostprocessingOps = 0
 Post Processing of observer signals. More...
 
std::vector< MIntm_postprocessingOps {}
 
MBool m_acaPostprocessingMode = false
 
MString m_acaPostprocessingFile = ""
 
MInt m_timerGroup = -1
 
std::array< MInt, Timers::_countm_timers {}
 
std::vector< AcaSymBcm_symBc
 

Static Private Attributes

static constexpr MFloat m_gamma = 1.4
 

Additional Inherited Members

- Public Attributes inherited from Solver
std::set< MIntm_freeIndices
 
MBool m_singleAdaptation = false
 
MBool m_splitAdaptation = true
 
MBool m_saveSensorData = false
 
- Protected Member Functions inherited from Solver
 Solver (const MInt solverId, const MPI_Comm comm, const MBool isActive=true)
 
MFloat returnLoadRecord () const
 
MFloat returnIdleRecord () const
 
- Protected Attributes inherited from Solver
MFloat m_Re {}
 the Reynolds number More...
 
MFloat m_Ma {}
 the Mach number More...
 
MInt m_solutionInterval
 The number of timesteps before writing the next solution file. More...
 
MInt m_solutionOffset {}
 
std::set< MIntm_solutionTimeSteps
 
MInt m_restartInterval
 The number of timesteps before writing the next restart file. More...
 
MInt m_restartTimeStep
 
MInt m_restartOffset
 
MString m_solutionOutput
 
MBool m_useNonSpecifiedRestartFile = false
 
MBool m_initFromRestartFile
 
MInt m_residualInterval
 The number of timesteps before writing the next residual. More...
 
const MInt m_solverId
 a unique solver identifier More...
 
MFloatm_outerBandWidth = nullptr
 
MFloatm_innerBandWidth = nullptr
 
MIntm_bandWidth = nullptr
 
MBool m_restart = false
 
MBool m_restartFile = false
 

Detailed Description

template<MInt nDim>
class AcaSolver< nDim >

Reference for implementation/validation of FWH solver: 'Predition of far-field noise using the Ffowcs Williams-Hawkings method', Maximilian Kerstan, Master thesis, 2020.

Definition at line 78 of file acasolver.h.

Member Typedef Documentation

◆ ObserverDataCollector

template<MInt nDim>
using AcaSolver< nDim >::ObserverDataCollector = maia::acoustic_analogy::observer_collector::ObserverDataCollector<nDim>
private

Definition at line 82 of file acasolver.h.

◆ SourceParameters

template<MInt nDim>
using AcaSolver< nDim >::SourceParameters = maia::acoustic::SourceParameters
private

Definition at line 83 of file acasolver.h.

◆ SourceVars

template<MInt nDim>
using AcaSolver< nDim >::SourceVars = maia::acoustic::SourceVars
private

Definition at line 84 of file acasolver.h.

◆ SurfaceDataCollector

template<MInt nDim>
using AcaSolver< nDim >::SurfaceDataCollector = maia::acoustic_analogy::collector::SurfaceDataCollector<nDim>
private

Definition at line 81 of file acasolver.h.

◆ Timers

template<MInt nDim>
using AcaSolver< nDim >::Timers = maia::acoustic::Timers_
private

Definition at line 85 of file acasolver.h.

Member Enumeration Documentation

◆ NONDIMBASIS

template<MInt nDim>
enum AcaSolver::NONDIMBASIS
private
Enumerator
NONDIMACA 
NONDIMSTAGNATION 
NONDIMLB 

Definition at line 87 of file acasolver.h.

87 {
88 NONDIMACA = 0,
90 NONDIMLB = 2,
91 };
@ NONDIMACA
Definition: acasolver.h:88
@ NONDIMSTAGNATION
Definition: acasolver.h:89
@ NONDIMLB
Definition: acasolver.h:90

Constructor & Destructor Documentation

◆ AcaSolver()

template<MInt nDim>
AcaSolver< nDim >::AcaSolver ( const MInt  solverId,
const MPI_Comm  comm 
)

Definition at line 24 of file acasolver.cpp.

24: Solver(solverId, comm, true) {}
Parent class of all solvers This class is the base for all solvers. I.e. all solver class (e....
Definition: solver.h:29
MInt solverId() const
Return the solverId.
Definition: solver.h:425

◆ ~AcaSolver()

template<MInt nDim>
AcaSolver< nDim >::~AcaSolver ( )
inlineoverride

Definition at line 96 of file acasolver.h.

96 {
98 RECORD_TIMER_STOP(m_timers[Timers::SolverType]);
99 };
std::array< MInt, Timers::_count > m_timers
Definition: acasolver.h:448
void averageTimer()
Average all FWH timer over participating ranks.
Definition: acasolver.cpp:74

Member Function Documentation

◆ a_globalObserverCoordinate()

template<MInt nDim>
MFloat AcaSolver< nDim >::a_globalObserverCoordinate ( const MInt  globalObserverId,
const MInt  dir 
)
inlineprivate

Definition at line 165 of file acasolver.h.

165 {
166 return m_globalObserverCoordinates[globalObserverId * nDim + dir];
167 };
std::vector< MFloat > m_globalObserverCoordinates
Definition: acasolver.h:368

◆ a_globalObserverId()

template<MInt nDim>
MInt AcaSolver< nDim >::a_globalObserverId ( const MInt  localObserverId)
inlineprivate

Definition at line 163 of file acasolver.h.

163{ return localObserverId + m_offsetObserver; };
MInt m_offsetObserver
Collector for (local) observer data.
Definition: acasolver.h:371

◆ a_localObserverId()

template<MInt nDim>
MInt AcaSolver< nDim >::a_localObserverId ( const MInt  globalObserverId)
inlineprivate

Definition at line 155 of file acasolver.h.

155 {
156 if(globalObserverId < m_offsetObserver || (m_offsetObserver + m_noObservers) < globalObserverId) {
157 return -1;
158 } else {
159 return globalObserverId - m_offsetObserver;
160 }
161 };
MInt m_noObservers
Offset of local observer.
Definition: acasolver.h:372

◆ applySymmetryBc()

template<MInt nDim>
void AcaSolver< nDim >::applySymmetryBc ( const std::array< MFloat, nDim >  coord,
MFloat *const  p_complexVariables 
)
private

Apply symmetry boundary condition.

Author
Miro Gondrum
Date
15.06.2023
Parameters
[in]coordLocation of the observer
[out]p_complexVariablesOutput of complex p', length of 2*noSamples()

Calculates surface integral for mirrored observer points. The resulting complex pressure is then added to the image observer points.

Definition at line 4547 of file acasolver.cpp.

4547 {
4548 TRACE();
4549 const MInt noSym = m_symBc.size();
4550 if(noSym == 0) return;
4551 TERMM_IF_COND(noSym > 1, "WARNING: only implemented for one symmetry BC so far");
4552 auto transform = [](std::array<MFloat, nDim>& coord_, const AcaSymBc& bc) {
4553 const MFloat coordTimesNormal = std::inner_product(&coord_[0], &coord_[nDim], &bc.normal[0], .0);
4554 for(MInt d = 0; d < nDim; d++) {
4555 coord_[d] += -2 * coordTimesNormal * bc.normal[d] + 2 * bc.origin[d];
4556 }
4557 };
4558 MFloatScratchSpace complexVariables_(2 * noSamples(), AT_, "complexVariables_");
4559 // transform observer position
4560 std::array<MFloat, nDim> symCoord = coord;
4561 transform(symCoord, m_symBc[0]);
4562 // Calculate pressure for transformed point before adding to its 'image' observer
4563 calcSurfaceIntegralsForObserver(symCoord, complexVariables_.data());
4564 for(MInt i = 0; i < noSamples(); i++) {
4565 p_complexVariables[2 * i + 0] += complexVariables_[2 * i + 0];
4566 p_complexVariables[2 * i + 1] += complexVariables_[2 * i + 1];
4567 }
4568}
MInt noSamples()
Return number of samples (i.e. number of time steps)
Definition: acasolver.h:146
std::vector< AcaSymBc > m_symBc
Definition: acasolver.h:558
void calcSurfaceIntegralsForObserver(const std::array< MFloat, nDim > coord, MFloat *const p_complexVariables)
Calculate the FWH surface integrals for a certain observer location.
Definition: acasolver.cpp:1573
This class is a ScratchSpace.
Definition: scratch.h:758
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52

◆ averageTimer()

template<MInt nDim>
void AcaSolver< nDim >::averageTimer
private
Author
Miro Gondrum
Date
21.02.2024

Definition at line 74 of file acasolver.cpp.

74 {
75 // 0) map timer ids for safety
76 std::vector<MInt> timerIds_;
77 timerIds_.reserve(11);
78 timerIds_.emplace_back(m_timers[Timers::Run]);
79 timerIds_.emplace_back(m_timers[Timers::InitParallelization]);
80 timerIds_.emplace_back(m_timers[Timers::ReadSurfaceData]);
81 timerIds_.emplace_back(m_timers[Timers::InitObservers]);
82 timerIds_.emplace_back(m_timers[Timers::CalcSourceTerms]);
83 timerIds_.emplace_back(m_timers[Timers::WindowAndTransformSources]);
84 timerIds_.emplace_back(m_timers[Timers::CalcSurfaceIntegrals]);
85 timerIds_.emplace_back(m_timers[Timers::CombineSurfaceIntegrals]);
86 timerIds_.emplace_back(m_timers[Timers::BacktransformObservers]);
87 timerIds_.emplace_back(m_timers[Timers::SaveObserverSignals]);
88 timerIds_.emplace_back(m_timers[Timers::Postprocessing]);
89 const MInt noTimers = timerIds_.size();
90 // 1) fill buffer with local timer values
91 std::vector<MFloat> timerValues_;
92 timerValues_.reserve(noTimers);
93 for(MInt i = 0; i < noTimers; i++) {
94 timerValues_.emplace_back(RETURN_TIMER_TIME(timerIds_[i]));
95 }
96 // 2) collect values from all ranks and use max value
97 MPI_Allreduce(MPI_IN_PLACE, timerValues_.data(), noTimers, maia::type_traits<MFloat>::mpiType(), MPI_MAX, mpiComm(),
98 AT_, "MPI_IN_PLACE", "timerValues_");
99 for(MInt i = 0; i < noTimers; i++) {
100 SET_RECORD(timerIds_[i], timerValues_[i]);
101 }
102}
MPI_Comm mpiComm() const
Return the MPI communicator used by this solver.
Definition: solver.h:380
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce

◆ backtransformObservers()

template<MInt nDim>
void AcaSolver< nDim >::backtransformObservers
private

Definition at line 2348 of file acasolver.cpp.

2348 {
2349 TRACE();
2350 RECORD_TIMER_START(m_timers[Timers::BacktransformObservers]);
2351 printMessage("- Backtransforming the observer signals");
2352
2353 // Data buffer for backtransformed pressure data
2354 MFloatScratchSpace backtransform(noSamples() * 2, AT_, "backtransform");
2355
2356 // BACKTRANSFORM
2357 for(MInt obs = 0; obs < noObservers(); obs++) {
2358 // Copy the first calculated half to the other half starting from behind going to the middle
2359 // (since it is a two-sided frequency plot)
2360 for(MInt i = 1; i < noSamples() / 2; i++) {
2362 m_observerData.complexVariables(obs, 0, noSamples() - i, 1) =
2363 -1.0 * m_observerData.complexVariables(obs, 0, i, 1);
2364 }
2365
2366 std::fill_n(&backtransform[0], 2 * noSamples(), 0.0);
2367 // Backtransformation
2368 if(m_FastFourier == true && m_transformationType == 1) {
2369 FastFourierTransform(&m_observerData.complexVariables(obs, 0), noSamples(), -1, &backtransform[0], false);
2370 } else if(m_FastFourier == false || (m_FastFourier == true && m_transformationType == 0)) {
2371 DiscreteFourierTransform(&m_observerData.complexVariables(obs, 0), noSamples(), -1, &backtransform[0], false);
2372 }
2373
2374 // Storing the results in observer.variables since it is back in time domain (only real part)
2375 for(MInt i = 0; i < noSamples(); i++) {
2376 m_observerData.variables(obs, 0, i) = backtransform[2 * i];
2377 }
2378 }
2379
2380 RECORD_TIMER_STOP(m_timers[Timers::BacktransformObservers]);
2381}
ObserverDataCollector m_observerData
Coordinates of (global) observer points.
Definition: acasolver.h:369
MInt m_transformationType
Fourier type.
Definition: acasolver.h:363
MInt noObservers()
Return local number of observer points.
Definition: acasolver.h:149
MBool m_FastFourier
Can FFT be used?
Definition: acasolver.h:430
void DiscreteFourierTransform(MFloat *dataArray, const MInt size, const MInt dir, MFloat *result, const MBool inPlace)
Discrete Fourier transform (computational expensive O(n^2) instead of O(n*logn) compared to FFT)
Definition: acasolver.cpp:1500
void printMessage(const MString msg)
Info functions.
Definition: acasolver.h:203
void FastFourierTransform(MFloat *dataArray, const MInt size, const MInt dir, MFloat *result, const MBool inPlace)
Functions for Fourier Transformation.
Definition: acasolver.cpp:1411
MFloat & complexVariables(const MInt id, const MInt var)
Accessor for complex variables.
MFloat & variables(const MInt id, const MInt var)
Accessor for variables (return a reference to the start of the given variable in memory).

◆ calcFrequencies()

template<MInt nDim>
void AcaSolver< nDim >::calcFrequencies
private

Definition at line 1549 of file acasolver.cpp.

1549 {
1550 TRACE();
1551 printMessage("- Calculate frequencies");
1552 // Calculate frequencies, m_frequencies is already resized with noSamples
1553 // Numerical Recipes in C by Cambridge page 503
1554 // Structure: 0 +1 +2 +3 ... +noSamples/2 ... -3 -2 -1
1555 for(MInt i = 0, k = noSamples() - 1; i <= noSamples() / 2; k--, i++) {
1556 if(k > noSamples() / 2) {
1557 m_frequencies[k] = -1.0 * static_cast<MFloat>(i + 1) / (noSamples() * m_dt);
1558 }
1559 m_frequencies[i] = static_cast<MFloat>(i) / (noSamples() * m_dt);
1560 }
1561 // Frequencies from Hz --> rad/s: now omega
1562 for(MInt i = 0; i < noSamples(); i++) {
1563 m_frequencies[i] *= 2.0 * PI;
1564 }
1565}
std::vector< MFloat > m_frequencies
Definition: acasolver.h:434
MFloat m_dt
Constant time step size.
Definition: acasolver.h:418

◆ calcMinDistanceForObservers()

template<MInt nDim>
void AcaSolver< nDim >::calcMinDistanceForObservers ( MFloat *const  distMinObservers)
private

Definition at line 2069 of file acasolver.cpp.

2069 {
2070 if(m_fwhTimeShiftType == 0) return;
2071
2072 // Calculate Mach number and the Prandtl-Glauert-Factor
2073 const MFloat mach = sqrt(std::inner_product(&m_MaVec[0], &m_MaVec[nDim], &m_MaVec[0], 0.0));
2074 const MFloat betaSq = 1.0 - mach * mach;
2075
2076 printMessage("- Loop over observers to find minimum distance from the source to the observers");
2077 for(MInt k = 0; k < globalNoObservers(); k++) {
2078 MFloat distMinLocal = std::numeric_limits<MFloat>::max();
2079
2080 // Get observer coordinates
2081 const std::array<MFloat, nDim> coord = getGlobalObserverCoordinates(k);
2082
2083 // SURFACE LOOP
2084 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
2085 MFloat* surfCoordinates = &m_surfaceData.surfaceCoordinates(segmentId);
2086
2087 if constexpr(nDim == 3) {
2088 // Geometric Distance & Coordinate Transformation
2089 MFloat distX = coord[0] - surfCoordinates[0];
2090 MFloat distY = coord[1] - surfCoordinates[1];
2091 MFloat distZ = coord[2] - surfCoordinates[2];
2092 transformCoordinatesToFlowDirection3D(&distX, &distY, &distZ);
2093
2094 // Effective Acoustic Distance
2095 const MFloat R = sqrt(distX * distX + betaSq * (distY * distY + distZ * distZ));
2096 const MFloat dist = (R - mach * distX) / betaSq;
2097
2098 // Find the minimum distance of all segments
2099 distMinLocal = (dist < distMinLocal) ? dist : distMinLocal;
2100 } else if constexpr(nDim == 2) {
2101 TERMM(1, "Time Domain FW-H not implimented in 2D: Requires free space Green function in 2D");
2102 } // End of the dimension switch
2103 } // End of surface loop
2104
2105 distMinObservers[k] = distMinLocal;
2106 } // End of observer loop
2107
2108 MPI_Allreduce(MPI_IN_PLACE, &distMinObservers[0], globalNoObservers(), type_traits<MFloat>::mpiType(), MPI_MIN,
2109 mpiComm(), AT_, "MPI_IN_PLACE", "distMinObservers");
2110
2111 if(m_fwhTimeShiftType == 2) {
2112 const MFloat disMinGlobal = *std::min_element(distMinObservers, distMinObservers + globalNoObservers());
2113 std::fill(distMinObservers, distMinObservers + globalNoObservers(), disMinGlobal);
2114 if(domainId() == 0) {
2115 std::cout << "Apply universal time shift for all observers = " << disMinGlobal << std::endl;
2116 }
2117 }
2118}
void transformCoordinatesToFlowDirection3D(MFloat *const fX, MFloat *const fY, MFloat *const fZ)
Definition: acasolver.cpp:2006
std::array< MFloat, nDim > getGlobalObserverCoordinates(const MInt globalObserverId)
Accessor for global observer coordinates.
Definition: acasolver.h:169
MInt totalNoSurfaceElements()
Return total number of (local) surfaces elements.
Definition: acasolver.h:138
MFloat m_MaVec[3]
Mach vector.
Definition: acasolver.h:421
MInt globalNoObservers()
Return number of observer points.
Definition: acasolver.h:153
SurfaceDataCollector m_surfaceData
Collector for surface data.
Definition: acasolver.h:344
MInt m_fwhTimeShiftType
Definition: acasolver.h:348
virtual MInt domainId() const
Return the domainId (rank)
Definition: solver.h:383
MFloat & surfaceCoordinates(const MInt id)
Accessor for surface element coordinates.
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54

◆ calcObsPressureAnalytic()

template<MInt nDim>
void AcaSolver< nDim >::calcObsPressureAnalytic
private

Definition at line 2583 of file acasolver.cpp.

2583 {
2584 TRACE();
2585
2586 const MInt noVars = (m_acousticMethod == FWH_METHOD) ? nDim + 2 : nDim + 1;
2587 MFloatScratchSpace vars(noVars, noObservers(), noSamples(), AT_, "varP");
2588 vars.fill(0.0);
2589
2590 for(MInt obsId = 0; obsId < noObservers(); obsId++) {
2591 // Pointers to pass to functions
2592 const MFloat* obsCoord = &m_observerData.observerCoordinates(obsId);
2593 SourceVars sourceVars;
2595 sourceVars.p = &vars(FWH::P, obsId, 0);
2596 sourceVars.u = &vars(FWH::U, obsId, 0);
2597 sourceVars.v = &vars(FWH::V, obsId, 0);
2598 sourceVars.w = &vars(FWH::W, obsId, 0);
2599 sourceVars.rho = &vars(FWH::RHO, obsId, 0);
2600 } else {
2601 sourceVars.p = &vars(FWH_APE::PP, obsId, 0);
2602 sourceVars.u = &vars(FWH_APE::UP, obsId, 0);
2603 sourceVars.v = &vars(FWH_APE::VP, obsId, 0);
2604 sourceVars.w = &vars(FWH_APE::WP, obsId, 0);
2605 }
2606
2607 if constexpr(nDim == 2) {
2608 switch(m_sourceType) {
2609 case 0: {
2610 genMonopoleAnalytic2D(obsCoord, m_sourceParameters, sourceVars);
2611 break;
2612 }
2613 case 1: {
2614 genDipoleAnalytic2D(obsCoord, m_sourceParameters, sourceVars);
2615 break;
2616 }
2617 case 2: {
2618 genQuadrupoleAnalytic2D(obsCoord, m_sourceParameters, sourceVars);
2619 break;
2620 }
2621 case 3: {
2623 break;
2624 }
2625 default: {
2626 TERMM(1, "source type not implemented");
2627 break;
2628 }
2629 }
2630 } else {
2631 switch(m_sourceType) {
2632 case 0: {
2633 genMonopoleAnalytic3D(obsCoord, m_sourceParameters, sourceVars);
2634 break;
2635 }
2636 case 1: {
2637 genDipoleAnalytic3D(obsCoord, m_sourceParameters, sourceVars);
2638 break;
2639 }
2640 case 2: {
2641 genQuadrupoleAnalytic3D(obsCoord, m_sourceParameters, sourceVars);
2642 break;
2643 }
2644 default: {
2645 TERMM(1, "source type not implemented");
2646 break;
2647 }
2648 }
2649 }
2650 }
2651
2652 // OUTPUT
2653 using namespace maia::parallel_io;
2654 const MString fileName = outputDir() + m_outputFilePrefix + "obsPressAnalytic" + ParallelIo::fileExt();
2655
2656 ParallelIo file(fileName, PIO_REPLACE, mpiComm());
2657
2658 ParallelIo::size_type dimSizes[] = {globalNoObservers(), noSamples()};
2659 file.defineArray(PIO_FLOAT, "obsPressAnalytic", 2, &dimSizes[0]);
2660
2661 file.setOffset(noObservers(), observerOffset(), 2);
2663 file.writeArray(&vars(FWH::P, 0, 0), "obsPressAnalytic");
2664 } else {
2665 file.writeArray(&vars(FWH_APE::PP, 0, 0), "obsPressAnalytic");
2666 }
2667}
maia::acoustic::SourceParameters m_sourceParameters
Parameter vector.
Definition: acasolver.h:398
void genQuadrupoleAnalytic2D(const MFloat *coord, const SourceParameters &param, SourceVars &vars)
Quadrupole.
Definition: acasolver.cpp:4307
void genDipoleAnalytic2D(const MFloat *coord, const SourceParameters &param, SourceVars &vars)
Dipole.
Definition: acasolver.cpp:4160
MInt m_acousticMethod
Acoustic extrapolation method to use, see enum ExtrapolationMethods in enums.h.
Definition: acasolver.h:347
void genQuadrupoleAnalytic3D(const MFloat *coord, const SourceParameters &param, SourceVars &vars)
3D quadrupole analytic
Definition: acasolver.cpp:4409
void genDipoleAnalytic3D(const MFloat *coord, const SourceParameters &param, SourceVars &vars)
3D dipole analytic
Definition: acasolver.cpp:4233
void genMonopoleAnalytic3D(const MFloat *coord, const SourceParameters &param, SourceVars &vars)
3D analytic monopole generation
Definition: acasolver.cpp:4097
void genMonopoleAnalytic2D(const MFloat *coord, const SourceParameters &param, SourceVars &vars)
Monopole.
Definition: acasolver.cpp:4035
void genVortexConvectionAnalytic2D(const MFloat *obsCoord, const SourceParameters &m_sourceParameters, SourceVars &sourceVars)
Inviscid vortex convection.
Definition: acasolver.cpp:4506
MString m_outputFilePrefix
Input directory.
Definition: acasolver.h:380
maia::acoustic::SourceVars SourceVars
Definition: acasolver.h:84
MInt observerOffset()
Return local number of observer points.
Definition: acasolver.h:151
MInt m_sourceType
Source Type.
Definition: acasolver.h:395
MString outputDir() const
Return the directory for output files.
Definition: solver.h:407
MFloat & observerCoordinates(const MInt id)
Accessor for surface element coordinates.
@ FWH_METHOD
Definition: enums.h:378
std::basic_string< char > MString
Definition: maiatypes.h:55
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
static constexpr const MInt WP
Definition: acasolver.h:508
static constexpr const MInt UP
Definition: acasolver.h:506
static constexpr const MInt PP
Definition: acasolver.h:509
static constexpr const MInt VP
Definition: acasolver.h:507
static constexpr const MInt W
Definition: acasolver.h:456
static constexpr const MInt V
Definition: acasolver.h:455
static constexpr const MInt RHO
Definition: acasolver.h:457
static constexpr const MInt P
Definition: acasolver.h:458
static constexpr const MInt U
Definition: acasolver.h:454

◆ calcSourceTerms()

template<MInt nDim>
void AcaSolver< nDim >::calcSourceTerms
private

Compute source terms for all surface elements depending on the selected method.

Definition at line 879 of file acasolver.cpp.

879 {
880 TRACE();
881 RECORD_TIMER_START(m_timers[Timers::CalcSourceTerms]);
882 printMessage("- Calculate source terms");
883
884 // Note: totalNoSurfaceElements() returns the local, total number of elements for a surface
885 // (may differ from domain to domain)
886
888 m_log << "Using Frequency-Domain FW-H Formulation" << std::endl;
889 for(MInt i = 0; i < totalNoSurfaceElements(); i++) {
891 }
892 } else if(string2enum(solverMethod()) == MAIA_FWH_TIME) {
893 m_log << "Using Farassat 1A Time-Domain FW-H Formulation" << std::endl;
894 for(MInt i = 0; i < totalNoSurfaceElements(); i++) {
896 }
897 } else {
898 TERMM(1, "Unknown solverMethod");
899 }
900
901 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceTerms]);
902}
void calcSourceTermsFwhTime(const MInt segmentId)
Calculate FWH source terms for the time domain FWH formulation Reference: [1] Brentner,...
Definition: acasolver.cpp:1062
void calcSourceTermsFwhFreq(const MInt segmentId)
Source term compute kernels.
Definition: acasolver.cpp:909
MString solverMethod() const
Return the solverMethod of this solver.
Definition: solver.h:413
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ MAIA_FWH_TIME
Definition: enums.h:102
@ MAIA_FWH_FREQUENCY
Definition: enums.h:101
InfoOutFile m_log

◆ calcSourceTermsFwhFreq()

template<MInt nDim>
void AcaSolver< nDim >::calcSourceTermsFwhFreq ( const MInt  segmentId)
private

Calculate FWH source terms for the frequency FWH formulation Reference: [1] Lockard, D.P., 2000. An efficient, two-dimensional ... doi.org/10.1006/jsvi.1999.2522 [2] Lockard, D.P., 2002, A comparison of Ffowcs ... doi.org/10.2514/6.2002-2580.

Definition at line 909 of file acasolver.cpp.

909 {
910 TRACE();
911
912 // Get pointer to normal vector
913 const MFloat* const normal = &m_surfaceData.surfaceNormal(segmentId);
914 // First two normal vector components (2D)
915 const MFloat dfdx = normal[0];
916 const MFloat dfdy = normal[1];
917 // Mach numbers (2D)
918 const MFloat Max = m_MaVec[0];
919 const MFloat May = m_MaVec[1];
920
921 const MFloat c_inf = 1.0; // by definition
922 const MFloat rho_inf = 1.0; // by definition
923 const MFloat p_inf = rho_inf * (c_inf * c_inf) / m_gamma;
924 const MFloat noSamplesInv = 1.0 / noSamples();
925
926 if constexpr(nDim == 3) {
927 // Third normal vector component for 3D
928 const MFloat dfdz = normal[2];
929 // Third Mach number for 3D
930 const MFloat Maz = m_MaVec[2];
931
932 // Compute mean velocities
933 MFloat uMean = 0.0;
934 MFloat vMean = 0.0;
935 MFloat wMean = 0.0;
937 switch(m_fwhMeanStateType) {
938 case 0: { // Default: use infnity properties to compute u'
939 uMean = m_MaVec[0];
940 vMean = m_MaVec[1];
941 wMean = m_MaVec[2];
942 break;
943 }
944 case 1: { // Use mean velocities to compute u'
945 for(MInt t = 0; t < noSamples(); t++) {
946 uMean += m_surfaceData.variables(segmentId, FWH::U, t);
947 vMean += m_surfaceData.variables(segmentId, FWH::V, t);
948 wMean += m_surfaceData.variables(segmentId, FWH::W, t);
949 }
950 uMean *= noSamplesInv;
951 vMean *= noSamplesInv;
952 wMean *= noSamplesInv;
953 break;
954 }
955 default: {
956 TERMM(1, "fwh mean state type not implemented");
957 break;
958 }
959 }
960 }
961
962 // Time loop over all samples for 3D
963 maia::parallelFor<false>(0, noSamples(), [=](MInt t) {
964 // Get required variables (u', v', w', p, rho)
965 std::vector<MInt> VarDim;
966 MFloat up = 0.0;
967 MFloat vp = 0.0;
968 MFloat wp = 0.0;
969 MFloat p = 0.0;
970 MFloat rho = 0.0;
972 VarDim = {FWH::FX, FWH::FY, FWH::FZ, FWH::Q};
973 up = m_surfaceData.variables(segmentId, FWH::U, t) - uMean;
974 vp = m_surfaceData.variables(segmentId, FWH::V, t) - vMean;
975 wp = m_surfaceData.variables(segmentId, FWH::W, t) - wMean;
976 p = m_surfaceData.variables(segmentId, FWH::P, t);
977 rho = m_surfaceData.variables(segmentId, FWH::RHO, t);
978 } else if(m_acousticMethod == FWH_APE_METHOD) {
980 up = m_surfaceData.variables(segmentId, FWH_APE::UP, t);
981 vp = m_surfaceData.variables(segmentId, FWH_APE::VP, t);
982 wp = m_surfaceData.variables(segmentId, FWH_APE::WP, t);
983 p = m_surfaceData.variables(segmentId, FWH_APE::PP, t) + p_inf;
984 rho = m_surfaceData.variables(segmentId, FWH_APE::PP, t) + rho_inf;
985 }
986
987 const MFloat f1 = (up + Max) * dfdx + (vp + May) * dfdy + (wp + Maz) * dfdz;
988 const MFloat f2 = Max * dfdx + May * dfdy + Maz * dfdz;
989
990 // Calculation of source terms (3D) Fx, Fy, Fz and Q for each sample.
991 m_surfaceData.variables(segmentId, VarDim[0], t) = p * dfdx + rho * (up - Max) * f1 + Max * f2;
992 m_surfaceData.variables(segmentId, VarDim[1], t) = p * dfdy + rho * (vp - May) * f1 + May * f2;
993 m_surfaceData.variables(segmentId, VarDim[2], t) = p * dfdz + rho * (wp - Maz) * f1 + Maz * f2;
994 m_surfaceData.variables(segmentId, VarDim[3], t) = rho * f1 - f2;
995 });
996 } else {
997 // Compute mean velocities
998 MFloat uMean = 0.0;
999 MFloat vMean = 0.0;
1001 switch(m_fwhMeanStateType) {
1002 case 0: { // Default: use infnity properties to compute u'
1003 uMean = m_MaVec[0];
1004 vMean = m_MaVec[1];
1005 break;
1006 }
1007 case 1: { // Use mean velocities to compute u'
1008 for(MInt t = 0; t < noSamples(); t++) {
1009 uMean += m_surfaceData.variables(segmentId, FWH::U, t);
1010 vMean += m_surfaceData.variables(segmentId, FWH::V, t);
1011 }
1012 uMean = uMean * noSamplesInv;
1013 vMean = vMean * noSamplesInv;
1014 break;
1015 }
1016 default: {
1017 TERMM(1, "fwh mean state type not implemented");
1018 break;
1019 }
1020 }
1021 }
1022
1023 // Time loop over all samples for 2D
1024 maia::parallelFor<false>(0, noSamples(), [=](MInt t) {
1025 // Get required variables (u', v', p, rho)
1026 std::vector<MInt> VarDim;
1027 MFloat up = 0.0;
1028 MFloat vp = 0.0;
1029 MFloat p = 0.0;
1030 MFloat rho = 0.0;
1032 VarDim = {FWH::FX, FWH::FY, FWH::Q};
1033 up = m_surfaceData.variables(segmentId, FWH::U, t) - uMean;
1034 vp = m_surfaceData.variables(segmentId, FWH::V, t) - vMean;
1035 p = m_surfaceData.variables(segmentId, FWH::P, t);
1036 rho = m_surfaceData.variables(segmentId, FWH::RHO, t);
1037 } else if(m_acousticMethod == FWH_APE_METHOD) {
1038 VarDim = {FWH_APE::FX, FWH_APE::FY, FWH_APE::Q};
1039 up = m_surfaceData.variables(segmentId, FWH_APE::UP, t);
1040 vp = m_surfaceData.variables(segmentId, FWH_APE::VP, t);
1041 p = m_surfaceData.variables(segmentId, FWH_APE::PP, t) + p_inf;
1042 rho = m_surfaceData.variables(segmentId, FWH_APE::PP, t) + rho_inf;
1043 }
1044
1045 const MFloat f1 = (up + Max) * dfdx + (vp + May) * dfdy;
1046 const MFloat f2 = Max * dfdx + May * dfdy;
1047
1048 // Calculation of source terms (2D) Fx, Fy and Q for each sample.
1049 m_surfaceData.variables(segmentId, VarDim[0], t) = p * dfdx + rho * (up - Max) * f1 + Max * f2;
1050 m_surfaceData.variables(segmentId, VarDim[1], t) = p * dfdy + rho * (vp - May) * f1 + May * f2;
1051 m_surfaceData.variables(segmentId, VarDim[2], t) = rho * f1 - f2;
1052 });
1053 }
1054}
static constexpr MFloat m_gamma
Definition: acasolver.h:427
MInt m_fwhMeanStateType
Definition: acasolver.h:349
MFloat & variables(const MInt id, const MInt var)
Accessor for variables.
MFloat & surfaceNormal(const MInt id)
Accessor for surface normal.
@ FWH_APE_METHOD
Definition: enums.h:380
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
static constexpr const MInt FX
Definition: acasolver.h:511
static constexpr const MInt FZ
Definition: acasolver.h:513
static constexpr const MInt Q
Definition: acasolver.h:514
static constexpr const MInt FY
Definition: acasolver.h:512
static constexpr const MInt FX
Definition: acasolver.h:461
static constexpr const MInt Q
Definition: acasolver.h:464
static constexpr const MInt FZ
Definition: acasolver.h:463
static constexpr const MInt FY
Definition: acasolver.h:462

◆ calcSourceTermsFwhTime()

template<MInt nDim>
void AcaSolver< nDim >::calcSourceTermsFwhTime ( const MInt  segmentId)
private

Definition at line 1062 of file acasolver.cpp.

1062 {
1063 TRACE();
1064
1065 // Get pointer to normal vector
1066 const MFloat* const normal = &m_surfaceData.surfaceNormal(segmentId);
1067 const MFloat c_inf = 1.0; // by definition
1068 const MFloat rho_inf = 1.0; // by definition
1069 const MFloat p_inf = rho_inf * (c_inf * c_inf) / m_gamma;
1070 const MFloat noSamplesInv = 1.0 / noSamples();
1071
1072 if constexpr(nDim == 3) {
1073 // Compute mean variables
1074 MFloat uMean = 0.0;
1075 MFloat vMean = 0.0;
1076 MFloat wMean = 0.0;
1077 MFloat pMean = 0.0;
1079 switch(m_fwhMeanStateType) {
1080 case 0: { // Default: use infnity properties to compute u'
1081 uMean = m_MaVec[0];
1082 vMean = m_MaVec[1];
1083 wMean = m_MaVec[2];
1084 pMean = p_inf;
1085 break;
1086 }
1087 case 1: { // Use mean velocities to compute u'
1088 for(MInt t = 0; t < noSamples(); t++) {
1089 uMean += m_surfaceData.variables(segmentId, FWH::U, t);
1090 vMean += m_surfaceData.variables(segmentId, FWH::V, t);
1091 wMean += m_surfaceData.variables(segmentId, FWH::W, t);
1092 pMean += m_surfaceData.variables(segmentId, FWH::P, t);
1093 }
1094 uMean *= noSamplesInv;
1095 vMean *= noSamplesInv;
1096 wMean *= noSamplesInv;
1097 pMean *= noSamplesInv;
1098 break;
1099 }
1100 default: {
1101 TERMM(1, "fwh mean state type not implemented");
1102 break;
1103 }
1104 }
1105 }
1106
1107 // Set surface geometry properties
1108 // TODO: This assumes a stationary sampling surface! Impliment the version for moving surface...
1109 MFloat nx = normal[0];
1110 MFloat ny = normal[1];
1111 MFloat nz = normal[2];
1112 MFloat surfVX = -m_MaVec[0];
1113 MFloat surfVY = -m_MaVec[1];
1114 MFloat surfVZ = -m_MaVec[2];
1115
1116 maia::parallelFor<false>(0, noSamples(), [=](MInt tau) {
1117 // Get surface (f=0) velocity --> based on the ABSOLUTE frame of reference
1118 m_surfaceData.variables(segmentId, FWH_TIME::surfMX, tau) = surfVX;
1119 m_surfaceData.variables(segmentId, FWH_TIME::surfMY, tau) = surfVY;
1120 m_surfaceData.variables(segmentId, FWH_TIME::surfMZ, tau) = surfVZ;
1121
1122 // Get primative variables --> based on the ABSOLUTE frame of reference
1123 MFloat up = 0.0;
1124 MFloat vp = 0.0;
1125 MFloat wp = 0.0;
1126 MFloat pp = 0.0;
1127 MFloat rho = 0.0;
1129 up = m_surfaceData.variables(segmentId, FWH::U, tau) - uMean;
1130 vp = m_surfaceData.variables(segmentId, FWH::V, tau) - vMean;
1131 wp = m_surfaceData.variables(segmentId, FWH::W, tau) - wMean;
1132 pp = m_surfaceData.variables(segmentId, FWH::P, tau) - pMean;
1133 rho = m_surfaceData.variables(segmentId, FWH::RHO, tau);
1134 } else if(m_acousticMethod == FWH_APE_METHOD) {
1135 up = m_surfaceData.variables(segmentId, FWH_APE::UP, tau);
1136 vp = m_surfaceData.variables(segmentId, FWH_APE::VP, tau);
1137 wp = m_surfaceData.variables(segmentId, FWH_APE::WP, tau);
1138 pp = m_surfaceData.variables(segmentId, FWH_APE::PP, tau);
1139 rho = rho_inf + pp; // = rho_inf + p'/(c_inf * c_inf)
1140 }
1141
1142 // Compute sources
1143 const MFloat un = up * nx + vp * ny + wp * nz;
1144 const MFloat vn = surfVX * nx + surfVY * ny + surfVZ * nz;
1145 const MFloat deltaUn = un - vn;
1146
1147 m_surfaceData.variables(segmentId, FWH_TIME::srcUn, tau) = vn + rho / rho_inf * deltaUn;
1148 m_surfaceData.variables(segmentId, FWH_TIME::srcLX, tau) = pp * nx + rho * up * deltaUn;
1149 m_surfaceData.variables(segmentId, FWH_TIME::srcLY, tau) = pp * ny + rho * vp * deltaUn;
1150 m_surfaceData.variables(segmentId, FWH_TIME::srcLZ, tau) = pp * nz + rho * wp * deltaUn;
1151
1152 // Transform the source terms to the flow direction coordinate
1154 &m_surfaceData.variables(segmentId, FWH_TIME::surfMY, tau),
1155 &m_surfaceData.variables(segmentId, FWH_TIME::surfMZ, tau));
1157 &m_surfaceData.variables(segmentId, FWH_TIME::srcLY, tau),
1158 &m_surfaceData.variables(segmentId, FWH_TIME::srcLZ, tau));
1159
1160 /*// Debugging
1161 MFloat* surfCoordinates = &m_surfaceData.surfaceCoordinates(segmentId);
1162 if(segmentId == 0 && tau == 0) {
1163 m_log << "tau = " << tau
1164 << ", surfCoordinates[0] = " << surfCoordinates[0]
1165 << ", surfCoordinates[1] = " << surfCoordinates[1]
1166 << ", surfCoordinates[2] = " << surfCoordinates[2]
1167 << ", nx = " << normal[0]
1168 << ", ny = " << normal[1]
1169 << ", nz = " << normal[2]
1170 << ", surfVX = " << surfVX
1171 << ", surfVY = " << surfVY
1172 << ", surfVZ = " << surfVZ
1173 << ", up = " << up
1174 << ", vp = " << vp
1175 << ", wp = " << wp
1176 << ", rho = " << rho
1177 << ", pp = " << pp
1178 << ", un = " << un
1179 << ", vn = " << vn
1180 << ", deltaUn = " << deltaUn
1181 << ", srcUn = " << std::setprecision(16) << m_surfaceData.variables(segmentId, FWH_TIME::srcUn, tau)
1182 << ", srcLX = " << std::setprecision(16) << m_surfaceData.variables(segmentId, FWH_TIME::srcLX, tau)
1183 << ", srcLY = " << std::setprecision(16) << m_surfaceData.variables(segmentId, FWH_TIME::srcLY, tau)
1184 << ", srcLZ = " << std::setprecision(16) << m_surfaceData.variables(segmentId, FWH_TIME::srcLZ, tau)
1185 << std::endl;
1186 }*/
1187 });
1188 } else if constexpr(nDim == 2) {
1189 TERMM(1, "Time Domain FW-H not implimented in 2D: Requires free space Green function in 2D");
1190 } // End of dimension switch
1191}
static constexpr const MInt surfMZ
Definition: acasolver.h:488
static constexpr const MInt srcLY
Definition: acasolver.h:493
static constexpr const MInt surfMX
Definition: acasolver.h:486
static constexpr const MInt srcUn
Definition: acasolver.h:491
static constexpr const MInt srcLZ
Definition: acasolver.h:494
static constexpr const MInt srcLX
Definition: acasolver.h:492
static constexpr const MInt surfMY
Definition: acasolver.h:487

◆ calcSurfaceIntegralsAtSourceTime()

template<MInt nDim>
void AcaSolver< nDim >::calcSurfaceIntegralsAtSourceTime ( const MInt  globalObserverId)
private
Author
Zhe Yang
Date
15.05.2024 \Reference: Brentner, K. S. and F. Farassat, 1998, Analytical Comparison ... doi.org/10.2514/2.558
Parameters
[in]globalObserverId
[out]m_surfaceData.variables(segmentId,FWH_TIME::timeObs,tau)observer time
[out]m_surfaceData.variables(segmentId,FWH_TIME::fwhPP,tau)observer pressure signal

Definition at line 1866 of file acasolver.cpp.

1866 {
1867 // Get observer coordinates
1868 const std::array<MFloat, nDim> coord = getGlobalObserverCoordinates(globalObserverId);
1869
1870 // Calculate Mach number and the Prandtl-Glauert-Factor
1871 const MFloat mach = sqrt(std::inner_product(&m_MaVec[0], &m_MaVec[nDim], &m_MaVec[0], 0.0));
1872 const MFloat betaSq = 1.0 - mach * mach;
1873
1874 // Loop over all the source timeSteps
1875 maia::parallelFor<false>(0, noSamples(), [=](MInt tau) {
1876 if constexpr(nDim == 3) {
1877 // SURFACE LOOP
1878 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
1879 MFloat* surfCoordinates = &m_surfaceData.surfaceCoordinates(segmentId);
1880
1881 // Geometric Distance & Coordinate Transformation
1882 MFloat distX = coord[0] - surfCoordinates[0];
1883 MFloat distY = coord[1] - surfCoordinates[1];
1884 MFloat distZ = coord[2] - surfCoordinates[2];
1885 transformCoordinatesToFlowDirection3D(&distX, &distY, &distZ);
1886
1887 // Effective Acoustic Distance
1888 // Reference: Brès, G., 2010, A Ffowcs Williams - Hawkings ... doi.org/10.2514/6.2010-3711
1889 const MFloat R = sqrt(distX * distX + betaSq * (distY * distY + distZ * distZ));
1890 const MFloat dist = (R - mach * distX) / betaSq;
1891
1892 const MFloat invsersDist = 1.0 / dist;
1893 const MFloat invsersDistSq = invsersDist * invsersDist;
1894 const MFloat distUnitX = (distX - mach * R) * invsersDist / betaSq;
1895 const MFloat distUnitY = distY * invsersDist;
1896 const MFloat distUnitZ = distZ * invsersDist;
1897
1898 // compute observer time
1899 const MFloat timeSource = tau * m_dt;
1900 const MFloat timeObserver = timeSource + dist;
1901
1902 // Get surface Mach number and source terms
1903 const MFloat Mx = m_surfaceData.variables(segmentId, FWH_TIME::surfMX, tau);
1904 const MFloat My = m_surfaceData.variables(segmentId, FWH_TIME::surfMY, tau);
1905 const MFloat Mz = m_surfaceData.variables(segmentId, FWH_TIME::surfMZ, tau);
1906 const MFloat srcUn = m_surfaceData.variables(segmentId, FWH_TIME::srcUn, tau);
1907 const MFloat srcLX = m_surfaceData.variables(segmentId, FWH_TIME::srcLX, tau);
1908 const MFloat srcLY = m_surfaceData.variables(segmentId, FWH_TIME::srcLY, tau);
1909 const MFloat srcLZ = m_surfaceData.variables(segmentId, FWH_TIME::srcLZ, tau);
1910
1911 // Project variables on the radiation direction
1912 const MFloat Mr = distUnitX * Mx + distUnitY * My + distUnitZ * Mz;
1913 const MFloat inverseDopplerFactor = 1.0 / (1.0 - Mr);
1914 const MFloat inverseDopplerFactorSq = inverseDopplerFactor * inverseDopplerFactor;
1915 const MFloat Lr = distUnitX * srcLX + distUnitY * srcLY + distUnitZ * srcLZ;
1916 const MFloat LM = srcLX * Mx + srcLY * My + srcLZ * Mz;
1917
1918 // Compute time derivative in second order accuracy
1919 const MFloat dotMX = calcTimeDerivative(segmentId, FWH_TIME::surfMX, tau);
1920 const MFloat dotMY = calcTimeDerivative(segmentId, FWH_TIME::surfMY, tau);
1921 const MFloat dotMZ = calcTimeDerivative(segmentId, FWH_TIME::surfMZ, tau);
1922 const MFloat dotUn = calcTimeDerivative(segmentId, FWH_TIME::srcUn, tau);
1923 const MFloat dotLX = calcTimeDerivative(segmentId, FWH_TIME::srcLX, tau);
1924 const MFloat dotLY = calcTimeDerivative(segmentId, FWH_TIME::srcLY, tau);
1925 const MFloat dotLZ = calcTimeDerivative(segmentId, FWH_TIME::srcLZ, tau);
1926
1927 // Project time derivative on the radiation direction
1928 const MFloat dotMr = distUnitX * dotMX + distUnitY * dotMY + distUnitZ * dotMZ;
1929 const MFloat dotLr = distUnitX * dotLX + distUnitY * dotLY + distUnitZ * dotLZ;
1930
1931 const MFloat MrFactor0 = invsersDist * inverseDopplerFactorSq;
1932 const MFloat MrFactor1 =
1933 (dist * dotMr + Mr - mach * mach) * invsersDistSq * inverseDopplerFactor * inverseDopplerFactorSq;
1934
1935 // Compute Thickness Source
1936 const MFloat surfIntegralPPT_0 = dotUn * MrFactor0;
1937 const MFloat surfIntegralPPT_1 = srcUn * MrFactor1;
1938
1939 // Compute Loading Source
1940 const MFloat surfIntegralPPL_0 = dotLr * MrFactor0;
1941 const MFloat surfIntegralPPL_1 = (Lr - LM) * MrFactor0 * invsersDist;
1942 const MFloat surfIntegralPPL_2 = Lr * MrFactor1;
1943
1944 // Save the computed source value
1945 m_surfaceData.variables(segmentId, FWH_TIME::timeObs, tau) = timeObserver;
1946 m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, tau) =
1947 surfIntegralPPT_0 + surfIntegralPPT_1 + surfIntegralPPL_0 + surfIntegralPPL_1 + surfIntegralPPL_2;
1948 m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, tau) *= m_surfaceData.surfaceArea(segmentId);
1949
1950 /*// Debugging
1951 if(segmentId == 0 && tau == 0) {
1952 m_log << "tau = " << tau
1953 << ", timeSource = " << timeSource
1954 << ", timeObserver = " << timeObserver
1955 << ", coord[0] = " << coord[0]
1956 << ", coord[1] = " << coord[1]
1957 << ", coord[2] = " << coord[2]
1958 << ", surfCoordinates[0] = " << surfCoordinates[0]
1959 << ", surfCoordinates[1] = " << surfCoordinates[1]
1960 << ", surfCoordinates[2] = " << surfCoordinates[2]
1961 << ", distX = " << distX
1962 << ", distY = " << distY
1963 << ", distZ = " << distZ
1964 << ", dist = " << dist
1965 << ", distUnitX = " << distUnitX
1966 << ", distUnitY = " << distUnitY
1967 << ", distUnitZ = " << distUnitZ
1968 << ", dL = " << m_surfaceData.surfaceArea(segmentId)
1969 << ", srcUn = " << srcUn
1970 << ", dotUn = " << dotUn
1971 << ", Lr = " << Lr
1972 << ", dotLr = " << dotLr
1973 << ", LM = " << LM
1974 << ", Mr = " << Mr
1975 << ", dotMr = " << dotMr
1976 << ", MSq = " << MSq
1977 << ", MrFactor0 = " << MrFactor0
1978 << ", MrFactor1 = " << MrFactor1
1979 << ", surfIntegralPPT_0= " << surfIntegralPPT_0
1980 << ", surfIntegralPPT_1= " << surfIntegralPPT_1
1981 << ", surfIntegralPPL_0= " << surfIntegralPPL_0
1982 << ", surfIntegralPPL_1= " << surfIntegralPPL_1
1983 << ", surfIntegralPPL_2= " << surfIntegralPPL_2
1984 << std::endl;
1985 }*/
1986 } // End of surface loop
1987 } else if constexpr(nDim == 2) {
1988 TERMM(1, "Time Domain FW-H not implimented in 2D: Requires free space Green function in 2D");
1989 } // End of the dimension switch
1990 }); // End of the time loop
1991}
MFloat calcTimeDerivative(const MInt segmentId, const MInt varId, const MInt tau)
Definition: acasolver.cpp:2048
MFloat & surfaceArea(const MInt id)
Accessor for surface area (or segment length in 2D).
static constexpr const MInt fwhPP
Definition: acasolver.h:498
static constexpr const MInt timeObs
Definition: acasolver.h:497

◆ calcSurfaceIntegralsForObserver()

template<MInt nDim>
void AcaSolver< nDim >::calcSurfaceIntegralsForObserver ( const std::array< MFloat, nDim >  coord,
MFloat *const  p_complexVariables 
)
private
Author
Miro Gondrum
Date
15.06.2023
Parameters
[in]coordLocation of the observer
[out]p_complexVariablesOutput of complex p', length of 2*noSamples()

Definition at line 1573 of file acasolver.cpp.

1574 {
1575 RECORD_TIMER_START(m_timers[Timers::CalcSurfaceIntegrals]);
1576 std::vector<MInt> VarDimC;
1578 if constexpr(nDim == 3) {
1579 VarDimC = {FWH::FX_C, FWH::FY_C, FWH::FZ_C, FWH::Q_C};
1580 } else {
1581 VarDimC = {FWH::FX_C, FWH::FY_C, FWH::Q_C};
1582 }
1583 } else if(m_acousticMethod == FWH_APE_METHOD) {
1584 if constexpr(nDim == 3) {
1586 } else {
1588 }
1589 } else {
1590 TERMM(1, "Unknown acoustic method.");
1591 }
1592
1593 // Calculate Mach number
1594 const MFloat mach = sqrt(std::inner_product(&m_MaVec[0], &m_MaVec[nDim], &m_MaVec[0], 0.0));
1595 // Prandtl-Glauert-Factor
1596 const MFloat betaSq = 1.0 - mach * mach;
1597 const MFloat beta = sqrt(betaSq);
1598 const MFloat fbeta2 = 1 / betaSq;
1599
1600 if constexpr(nDim == 2) {
1601 const MFloat Max = m_MaVec[0];
1602 const MFloat May = m_MaVec[1];
1603
1604 MFloat theta = 0;
1605 if(!approx(Max, 0.0, MFloatEps) && !approx(May, 0.0, MFloatEps)) {
1606 theta = atan2(May, Max);
1607 }
1608
1609 // Pre-computing sine and cosine terms
1610 const MFloat sinTheta = sin(theta);
1611 const MFloat cosTheta = cos(theta);
1612
1613 // INNER LOOP OVER ALL FREQUENCIES (with only positive frequencies because bessel is not valid
1614 // for negativ nor zero). Since nw = 0 is always a 0, it is left out in the loop --> start at
1615 // nw = 1
1616 maia::parallelFor<false>(1, noSamples() / 2 + 1, [=](MInt nw) {
1617 // non-dimensionalized omega is already in m_frequencies
1618 const MFloat waveNumber = m_frequencies[nw];
1619
1620 // Set everything to 0
1621 MFloat integralFxRe = 0.0;
1622 MFloat integralFxIm = 0.0;
1623 MFloat integralFyRe = 0.0;
1624 MFloat integralFyIm = 0.0;
1625 MFloat integralQRe = 0.0;
1626 MFloat integralQIm = 0.0;
1627
1628 // LOOP OVER ALL LOCAL SURFACE ELEMENTS
1629 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
1630 // Calculation of Prandtl-Glauert-Coordinates
1631 // Division by reference length is leaved out bc it would cancel out later
1632 const MFloat* const surfCoordinates = &m_surfaceData.surfaceCoordinates(segmentId);
1633 const MFloat surfX = surfCoordinates[0];
1634 const MFloat surfY = surfCoordinates[1];
1635 const MFloat X = (coord[0] - surfX) * cosTheta + (coord[1] - surfY) * sinTheta;
1636 const MFloat Y = -1.0 * (coord[0] - surfX) * sinTheta + (coord[1] - surfY) * cosTheta;
1637
1638 const MFloat d = sqrt(X * X + betaSq * Y * Y);
1639 const MFloat fd = 1 / d;
1640
1641 // Argument in Hankelfunction argH and its derivatives
1642 const MFloat argH = waveNumber * fbeta2 * d;
1643 const MFloat dargHdxi = waveNumber * fbeta2 * fd * (-1.0 * X * cosTheta + betaSq * Y * sinTheta);
1644 const MFloat dargHdeta = waveNumber * fbeta2 * fd * (-1.0 * X * sinTheta - betaSq * Y * cosTheta);
1645
1646 // Argument for exp function and its derivaties
1647 const MFloat argExp = mach * waveNumber * X * fbeta2;
1648 const MFloat dargEdxi = -1.0 * mach * waveNumber * cosTheta * fbeta2;
1649 const MFloat dargEdeta = -1.0 * mach * waveNumber * sinTheta * fbeta2;
1650 const MFloat C1 = 1.0 / (4.0 * beta);
1651
1652 const MFloat J0 = j0(argH);
1653 const MFloat J1 = j1(argH);
1654 const MFloat Y0 = y0(argH);
1655 const MFloat Y1 = y1(argH);
1656
1657 const MFloat cosargE = cos(argExp);
1658 const MFloat sinargE = sin(argExp);
1659
1660 // Calculation of the Green's function. y0, j0, y1 and j1 are used for Hankel function
1661 const MFloat greenValue_Re = C1 * (cosargE * Y0 - sinargE * J0);
1662 const MFloat greenValue_Im = C1 * (cosargE * J0 + sinargE * Y0);
1663
1664 // Calculation of the derivation of the Greenfunction resp. xi and eta
1665 const MFloat dGreendXi_Re =
1666 C1 * (dargEdxi * (-1.0 * cosargE * J0 - sinargE * Y0) + dargHdxi * (-1.0 * cosargE * Y1 + sinargE * J1));
1667 const MFloat dGreendXi_Im =
1668 C1 * (dargEdxi * (cosargE * Y0 - sinargE * J0) + dargHdxi * (-1.0 * cosargE * J1 - sinargE * Y1));
1669 const MFloat dGreendEta_Re =
1670 C1 * (dargEdeta * (-1.0 * cosargE * J0 - sinargE * Y0) + dargHdeta * (-1.0 * cosargE * Y1 + sinargE * J1));
1671 const MFloat dGreendEta_Im =
1672 C1 * (dargEdeta * (cosargE * Y0 - sinargE * J0) + dargHdeta * (-1.0 * cosargE * J1 - sinargE * Y1));
1673
1674 // Get Grid size dL
1675 const MFloat dL = m_surfaceData.surfaceArea(segmentId);
1676 // Get local values
1677 const MFloat FxRe = m_surfaceData.complexVariables(segmentId, VarDimC[0], nw, 0);
1678 const MFloat FxIm = m_surfaceData.complexVariables(segmentId, VarDimC[0], nw, 1);
1679
1680 const MFloat FyRe = m_surfaceData.complexVariables(segmentId, VarDimC[1], nw, 0);
1681 const MFloat FyIm = m_surfaceData.complexVariables(segmentId, VarDimC[1], nw, 1);
1682
1683 const MFloat QRe = m_surfaceData.complexVariables(segmentId, VarDimC[2], nw, 0);
1684 const MFloat QIm = m_surfaceData.complexVariables(segmentId, VarDimC[2], nw, 1);
1685
1686 // Calculate integral terms
1687 integralFxRe += dL * (FxRe * dGreendXi_Re - FxIm * dGreendXi_Im);
1688 integralFxIm += dL * (FxRe * dGreendXi_Im + FxIm * dGreendXi_Re);
1689
1690 integralFyRe += dL * (FyRe * dGreendEta_Re - FyIm * dGreendEta_Im);
1691 integralFyIm += dL * (FyRe * dGreendEta_Im + FyIm * dGreendEta_Re);
1692
1693 integralQRe += -1.0 * waveNumber * dL * (QRe * greenValue_Im + QIm * greenValue_Re);
1694 integralQIm += waveNumber * dL * (QRe * greenValue_Re - QIm * greenValue_Im);
1695 } // end segmentId Loop
1696
1697 // sum up all integral terms
1698 const MFloat integralRe = -1.0 * (integralFxRe + integralFyRe + integralQRe);
1699 const MFloat integralIm = -1.0 * (integralFxIm + integralFyIm + integralQIm);
1700
1701 // Store pressure values in observerData
1702 p_complexVariables[2 * nw + 0] = integralRe;
1703 p_complexVariables[2 * nw + 1] = integralIm;
1704 });
1705 } else if constexpr(nDim == 3) {
1706 const MFloat Max = m_MaVec[0];
1707 const MFloat May = m_MaVec[1];
1708 const MFloat Maz = m_MaVec[2];
1709
1710 MFloat theta = 0.0;
1711 MFloat alpha = 0.0;
1712 // Determination of the flow direction
1713 // Use approx(..., 0.0, MFloatEps) instead of Maz == 0.0 || May == 0.0. Compares Ma with a
1714 // really low number epsilon
1715 if(!approx(Maz, 0.0, MFloatEps) && !approx(Max, 0.0, MFloatEps)) {
1716 theta = atan2(Maz, Max);
1717 }
1718 if(!approx(May, 0.0, MFloatEps)) {
1719 alpha = asin(May / mach);
1720 }
1721
1722 // Precompute trigonometric values
1723 const MFloat sinAlpha = sin(alpha);
1724 const MFloat cosAlpha = cos(alpha);
1725 const MFloat sinTheta = sin(theta);
1726 const MFloat cosTheta = cos(theta);
1727
1728 // FREQUENCIE LOOP: only for positive frequencies without nw=0
1729 maia::parallelFor<false>(1, noSamples() / 2 + 1, [=](MInt nw) {
1730 // Calculate wave number: Non-dimensionalized omega is already saved in m_frequencies
1731 const MFloat waveNumber = m_frequencies[nw];
1732
1733 // Set values to zero
1734 MFloat integralFxRe = 0.0;
1735 MFloat integralFxIm = 0.0;
1736 MFloat integralFyRe = 0.0;
1737 MFloat integralFyIm = 0.0;
1738 MFloat integralFzRe = 0.0;
1739 MFloat integralFzIm = 0.0;
1740 MFloat integralQRe = 0.0;
1741 MFloat integralQIm = 0.0;
1742
1743 // SURFACE LOOP
1744 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
1745 MFloat* surfCoordinates = &m_surfaceData.surfaceCoordinates(segmentId);
1746
1747 const MFloat x = coord[0];
1748 const MFloat y = coord[1];
1749 const MFloat z = coord[2];
1750 const MFloat xi = surfCoordinates[0];
1751 const MFloat eta = surfCoordinates[1];
1752 const MFloat zeta = surfCoordinates[2];
1753
1754 /*
1755 // Version without Prandtl-Glauert
1756 const MFloat X = x - xi;
1757 const MFloat Y = y - eta;
1758 const MFloat Z = z - zeta;
1759 const MFloat R = sqrt(POW2(X) + POW2(Y) + POW2(Z));
1760
1761 const MFloat arg = waveNumber * R;
1762 const MFloat sinarg = sin(arg);
1763 const MFloat cosarg = cos(arg);
1764 const MFloat factor1 = waveNumber / (4.0 * PI * POW2(R));
1765 const MFloat factor2 = 1.0 / (4.0 * PI * POW3(R));
1766 const MFloat factorRe = -factor1 * sinarg - factor2 * cosarg;
1767 const MFloat factorIm = -factor1 * cosarg + factor2 * sinarg;
1768
1769 const MFloat greenValue_Re = -cosarg / (4.0 * PI * R);
1770 const MFloat greenValue_Im = sinarg / (4.0 * PI * R);
1771 const MFloat dGreendXi_Re = X * factorRe;
1772 const MFloat dGreendXi_Im = X * factorIm;
1773 const MFloat dGreendEta_Re = Y * factorRe;
1774 const MFloat dGreendEta_Im = Y * factorIm;
1775 const MFloat dGreendZeta_Re = Z * factorRe;
1776 const MFloat dGreendZeta_Im = Z * factorIm;
1777 */
1778
1779 // Version with Prandtl-Glauert, cf. Lockard2002
1780 const MFloat X = (x - xi) * cosAlpha * cosTheta + (y - eta) * sinAlpha + (z - zeta) * cosAlpha * sinTheta;
1781 // The Y coordinate differs from the paper, as there is a typo of the sign in front of the (z-zeta) term
1782 const MFloat Y = -(x - xi) * sinAlpha * cosTheta + (y - eta) * cosAlpha - (z - zeta) * sinAlpha * sinTheta;
1783 const MFloat Z = -(x - xi) * sinTheta + (z - zeta) * cosTheta;
1784 const MFloat d = std::sqrt(X * X + betaSq * (Y * Y + Z * Z));
1785 const MFloat k = waveNumber;
1786
1787 // partial d / partial xi
1788 const MFloat F1B4pid = 1.0 / (4.0 * PI * d);
1789 const MFloat d_xi = (-X * cosAlpha * cosTheta + betaSq * (Y * sinAlpha * cosTheta + Z * sinTheta)) / d;
1790 const MFloat d_eta = (-X * sinAlpha - betaSq * Y * cosAlpha) / d;
1791 const MFloat d_zeta = (-X * cosAlpha * sinTheta + betaSq * (-Y * sinAlpha * sinTheta - Z * cosTheta)) / d;
1792
1793 const MFloat arg = k * (mach * X - d) / betaSq;
1794 const MFloat cosArg = cos(arg);
1795 const MFloat sinArg = sin(arg);
1796
1797 // Pre-terms in the derivatives
1798 const MFloat P0 = F1B4pid * mach * k / betaSq;
1799 const MFloat P1 = F1B4pid / d;
1800 const MFloat P2 = F1B4pid * k / betaSq;
1801
1802 // clang-format off
1803 const MFloat greenValue_Re = - F1B4pid * cosArg;
1804 const MFloat greenValue_Im = - F1B4pid * sinArg;
1805 const MFloat dGreendXi_Re =-P0 * sinArg * cosAlpha * cosTheta + P1 * d_xi * cosArg - P2 * d_xi * sinArg;
1806 const MFloat dGreendXi_Im = P0 * cosArg * cosAlpha * cosTheta + P1 * d_xi * sinArg + P2 * d_xi * cosArg;
1807 const MFloat dGreendEta_Re =-P0 * sinArg * sinAlpha + P1 * d_eta * cosArg - P2 * d_eta * sinArg;
1808 const MFloat dGreendEta_Im = P0 * cosArg * sinAlpha + P1 * d_eta * sinArg + P2 * d_eta * cosArg;
1809 const MFloat dGreendZeta_Re =-P0 * sinArg * cosAlpha * sinTheta + P1 * d_zeta * cosArg - P2 * d_zeta * sinArg;
1810 const MFloat dGreendZeta_Im = P0 * cosArg * cosAlpha * sinTheta + P1 * d_zeta * sinArg + P2 * d_zeta * cosArg;
1811 // clang-format on
1812
1813 const MFloat dL = m_surfaceData.surfaceArea(segmentId);
1814
1815 const MFloat FxRe = m_surfaceData.complexVariables(segmentId, VarDimC[0], nw, 0);
1816 const MFloat FxIm = m_surfaceData.complexVariables(segmentId, VarDimC[0], nw, 1);
1817
1818 const MFloat FyRe = m_surfaceData.complexVariables(segmentId, VarDimC[1], nw, 0);
1819 const MFloat FyIm = m_surfaceData.complexVariables(segmentId, VarDimC[1], nw, 1);
1820
1821 const MFloat FzRe = m_surfaceData.complexVariables(segmentId, VarDimC[2], nw, 0);
1822 const MFloat FzIm = m_surfaceData.complexVariables(segmentId, VarDimC[2], nw, 1);
1823
1824 const MFloat QRe = m_surfaceData.complexVariables(segmentId, VarDimC[3], nw, 0);
1825 const MFloat QIm = m_surfaceData.complexVariables(segmentId, VarDimC[3], nw, 1);
1826
1827 // Calculation of integrals
1828 integralFxRe += dL * (FxRe * dGreendXi_Re - FxIm * dGreendXi_Im);
1829 integralFxIm += dL * (FxRe * dGreendXi_Im + FxIm * dGreendXi_Re);
1830
1831 integralFyRe += dL * (FyRe * dGreendEta_Re - FyIm * dGreendEta_Im);
1832 integralFyIm += dL * (FyRe * dGreendEta_Im + FyIm * dGreendEta_Re);
1833
1834 integralFzRe += dL * (FzRe * dGreendZeta_Re - FzIm * dGreendZeta_Im);
1835 integralFzIm += dL * (FzRe * dGreendZeta_Im + FzIm * dGreendZeta_Re);
1836
1837 integralQRe += -1.0 * waveNumber * dL * (QRe * greenValue_Im + QIm * greenValue_Re);
1838 integralQIm += waveNumber * dL * (QRe * greenValue_Re - QIm * greenValue_Im);
1839 } // End of segmentId loop
1840
1841 // sum up all integral terms
1842 const MFloat integralRe = -1.0 * (integralFxRe + integralFyRe + integralFzRe + integralQRe);
1843 const MFloat integralIm = -1.0 * (integralFxIm + integralFyIm + integralFzIm + integralQIm);
1844
1845 // Saving Pressure in Observerdata variable p for each positive frequencie nw between 1 and
1846 // size/2+1. 0 = RE; 1 = IM
1847 p_complexVariables[2 * nw + 0] = integralRe;
1848 p_complexVariables[2 * nw + 1] = integralIm;
1849 });
1850 }
1851 // nw = 0 is not defined and therefore set to zero to avoid "NaN-errors"
1852 const MInt nw = 0;
1853 p_complexVariables[2 * nw + 0] = 0.0;
1854 p_complexVariables[2 * nw + 1] = 0.0;
1855 RECORD_TIMER_STOP(m_timers[Timers::CalcSurfaceIntegrals]);
1856}
MFloat & complexVariables(const MInt id, const MInt var)
Accessor for complex variables.
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125
static constexpr const MInt FY_C
Definition: acasolver.h:520
static constexpr const MInt Q_C
Definition: acasolver.h:522
static constexpr const MInt FZ_C
Definition: acasolver.h:521
static constexpr const MInt FX_C
Definition: acasolver.h:519
static constexpr const MInt Q_C
Definition: acasolver.h:472
static constexpr const MInt FZ_C
Definition: acasolver.h:471
static constexpr const MInt FY_C
Definition: acasolver.h:470
static constexpr const MInt FX_C
Definition: acasolver.h:469
define array structures

◆ calcTimeDerivative()

template<MInt nDim>
MFloat AcaSolver< nDim >::calcTimeDerivative ( const MInt  segmentId,
const MInt  varId,
const MInt  tau 
)
private

Definition at line 2048 of file acasolver.cpp.

2048 {
2049 // Compute time derivative in second order accuarate
2050 MFloat dotVar = 0.0;
2051
2052 if(tau == 0) {
2053 dotVar = -1.0 * m_surfaceData.variables(segmentId, varId, tau + 2)
2054 + 4.0 * m_surfaceData.variables(segmentId, varId, tau + 1)
2055 - 3.0 * m_surfaceData.variables(segmentId, varId, tau);
2056 } else if(tau == noSamples() - 1) {
2057 dotVar = +3.0 * m_surfaceData.variables(segmentId, varId, tau)
2058 - 4.0 * m_surfaceData.variables(segmentId, varId, tau - 1)
2059 + 1.0 * m_surfaceData.variables(segmentId, varId, tau - 2);
2060 } else {
2061 dotVar = +1.0 * m_surfaceData.variables(segmentId, varId, tau + 1)
2062 - 1.0 * m_surfaceData.variables(segmentId, varId, tau - 1);
2063 }
2064 return (dotVar / 2.0 / m_dt);
2065}

◆ calculateObserverInFrequency()

template<MInt nDim>
void AcaSolver< nDim >::calculateObserverInFrequency
private

Definition at line 2294 of file acasolver.cpp.

2294 {
2295 printMessage("- Calculate observer signals in frequency domain");
2296 ScratchSpace<MFloat> complexVariablesBuffer(2 * noSamples(), AT_, "complexVariablesBuffer");
2297 complexVariablesBuffer.fill(0.0);
2298 MFloat* const p_complexVariables = complexVariablesBuffer.data();
2299 for(MInt globalObserverId = 0; globalObserverId < globalNoObservers(); globalObserverId++) {
2300 std::array<MFloat, nDim> coord = getGlobalObserverCoordinates(globalObserverId);
2301 calcSurfaceIntegralsForObserver(coord, p_complexVariables);
2302 applySymmetryBc(coord, p_complexVariables);
2303 combineSurfaceIntegrals(globalObserverId, p_complexVariables);
2304 }
2305}
void applySymmetryBc(const std::array< MFloat, nDim > coord, MFloat *const p_complexVariables)
Symmetry boundary condition.
Definition: acasolver.cpp:4547
void combineSurfaceIntegrals(const MInt globalObserverId, MFloat *const p_complexVariables)
Combine the FWH surface integrals of all ranks.
Definition: acasolver.cpp:2203

◆ calculateObserverInTime()

template<MInt nDim>
void AcaSolver< nDim >::calculateObserverInTime
private

Definition at line 2309 of file acasolver.cpp.

2309 {
2310 // Set memory for min observer distance
2311 ScratchSpace<MFloat> distMinBuffer(globalNoObservers(), AT_, "distMinBuffer");
2312 distMinBuffer.fill(0.0);
2313 MFloat* const distMinObservers = distMinBuffer.data();
2314
2315 // Set memory for observer pressure signal
2316 ScratchSpace<MFloat> perturbedPressureBuffer(noSamples(), AT_, "perturbedPressureBuffer");
2317 perturbedPressureBuffer.fill(0.0);
2318 MFloat* const p_perturbedFWH = perturbedPressureBuffer.data();
2319
2320 printMessage("- Calculate observer signals in time domain");
2321 calcMinDistanceForObservers(distMinObservers);
2322
2323 for(MInt globalObserverId = 0; globalObserverId < globalNoObservers(); globalObserverId++) {
2324 // m_log << "Compute for observer = " << globalObserverId << "/" << globalNoObservers() << std::endl;
2325 calcSurfaceIntegralsAtSourceTime(globalObserverId);
2326 interpolateFromSourceToObserverTime(distMinObservers[globalObserverId], p_perturbedFWH);
2327 combineSurfaceIntegralsInTime(globalObserverId, p_perturbedFWH);
2328 }
2329}
void interpolateFromSourceToObserverTime(const MFloat distMinObservers, MFloat *const p_perturbedFWH)
Interpolate the observer pressure signal from source time to observer time using the advanced time ap...
Definition: acasolver.cpp:2123
void combineSurfaceIntegralsInTime(const MInt globalObserverId, MFloat *const p_perturbedFWH)
Combine the FWH surface integrals of the time domain method of all ranks.
Definition: acasolver.cpp:2253
void calcSurfaceIntegralsAtSourceTime(const MInt globalObserverId)
Calculate the FWH surface integrals for a certain observer using the time-domain formulation.
Definition: acasolver.cpp:1866
void calcMinDistanceForObservers(MFloat *const distMinObservers)
Find the minimum distance from the surface elements to the observers.
Definition: acasolver.cpp:2069

◆ calcWindowFactors()

template<MInt nDim>
void AcaSolver< nDim >::calcWindowFactors ( MFloat *const  p_window)
private

Definition at line 1195 of file acasolver.cpp.

1195 {
1196 const MFloat N = static_cast<MFloat>(noSamples());
1197 MFloat normFactor = 1.0;
1198
1199 switch(m_windowType) {
1200 case WINDOW::NONE: {
1201 m_log << " - using no window function" << std::endl;
1202 break;
1203 }
1204 case WINDOW::HANNING: {
1205 m_log << " - using Hanning window function" << std::endl;
1206 MFloat sum_w_sq = 0.0;
1207 for(MInt t = 0; t < noSamples(); t++) {
1208 const MFloat w = 0.5 * (1.0 - cos(2.0 * PI * t / N));
1209 sum_w_sq += w * w;
1210 p_window[t] = w;
1211 }
1212 normFactor = 1.0 / sqrt(sum_w_sq / N);
1213 break;
1214 }
1215 case WINDOW::HAMMING: {
1216 m_log << " - using Hamming window function" << std::endl;
1217 MFloat sum_w_sq = 0.0;
1218 for(MInt t = 0; t < noSamples(); t++) {
1219 const MFloat w = 0.54 - 0.46 * cos(2.0 * PI * t / N);
1220 sum_w_sq += w * w;
1221 p_window[t] = w;
1222 }
1223 normFactor = 1.0 / sqrt(sum_w_sq / N);
1224 break;
1225 }
1226 case WINDOW::MODHANNING: {
1227 m_log << " - using modified-Hanning window function" << std::endl;
1228 MFloat sum_w_sq = 0.0;
1229 for(MInt t = 0; t < noSamples(); t++) {
1230 MFloat w = 0.0;
1231 if(t < N / 8.0 || t > 7.0 * N / 8.0) {
1232 w = 0.5 * (1.0 - cos(8.0 * PI * t / N));
1233 } else {
1234 w = 1.0;
1235 }
1236 sum_w_sq += w * w;
1237 p_window[t] = w;
1238 }
1239 normFactor = 1.0 / sqrt(sum_w_sq / N);
1240 break;
1241 }
1242 default: {
1243 TERMM(1, "Invalid window type: '" + std::to_string(m_windowType) + "'");
1244 break;
1245 }
1246 }
1247 m_log << " - normalization factor: " << normFactor << std::endl;
1248 m_windowNormFactor = normFactor;
1249}
MInt m_windowType
Window type.
Definition: acasolver.h:358
MFloat m_windowNormFactor
Normalization factor of window.
Definition: acasolver.h:360
static constexpr const MInt MODHANNING
Definition: acasolver.h:542
static constexpr const MInt HANNING
Definition: acasolver.h:540
static constexpr const MInt NONE
Definition: acasolver.h:539
static constexpr const MInt HAMMING
Definition: acasolver.h:541

◆ changeDimensionsObserverData()

template<MInt nDim>
void AcaSolver< nDim >::changeDimensionsObserverData
private

Definition at line 4816 of file acasolver.cpp.

4816 {
4817 printMessage("- Change dimension of observer data");
4818 if(approx(m_aca2Output.frequency, 1.0, MFloatEps)) {
4819 for(MInt i = 0; i < noSamples(); i++) {
4821 }
4822 }
4823 if(approx(m_aca2Output.pressure, 1.0, MFloatEps)) {
4824 for(MInt obs = 0; obs < noObservers(); obs++) {
4825 for(MInt t = 0; t < noSamples(); t++) {
4827 }
4828 }
4829 for(MInt obs = 0; obs < noObservers(); obs++) {
4830 for(MInt f = 0; f < noSamples(); f++) {
4833 }
4834 }
4835 }
4836 if(approx(m_aca2Output.time, 1.0, MFloatEps)) {
4838 for(MInt i = 0; i < noSamples(); i++) {
4840 }
4841 }
4842}
std::vector< MFloat > m_times
Storage for times and frequencies.
Definition: acasolver.h:433
struct AcaSolver::ConversionFactors m_aca2Output

◆ changeDimensionsSurfaceData()

template<MInt nDim>
void AcaSolver< nDim >::changeDimensionsSurfaceData
private

Definition at line 4784 of file acasolver.cpp.

4784 {
4785 // All variables which are read in need to be non-dimensionalized with the freestream c and rho.
4786 // Index 0 in this (and only in this) function descripes the stagnation state.
4787 m_log << "Change dimensions from stagnation to freestream state" << std::endl;
4788
4789 // APE or not APE? That is the question
4790 const MInt dummy_u = (m_acousticMethod == FWH_METHOD) ? FWH::U : FWH_APE::UP;
4791 const MInt dummy_v = (m_acousticMethod == FWH_METHOD) ? FWH::V : FWH_APE::VP;
4792 const MInt dummy_w = (m_acousticMethod == FWH_METHOD) ? FWH::W : FWH_APE::WP;
4793 const MInt dummy_p = (m_acousticMethod == FWH_METHOD) ? FWH::P : FWH_APE::PP;
4794
4795 // Apply norm factor to the variables
4796 for(MInt seg = 0; seg < totalNoSurfaceElements(); seg++) {
4797 for(MInt t = 0; t < noSamples(); t++) {
4798 m_surfaceData.variables(seg, dummy_u, t) *= m_input2Aca.velocity;
4799 m_surfaceData.variables(seg, dummy_v, t) *= m_input2Aca.velocity;
4800 if constexpr(nDim == 3) m_surfaceData.variables(seg, dummy_w, t) *= m_input2Aca.velocity;
4801 m_surfaceData.variables(seg, dummy_p, t) *= m_input2Aca.pressure;
4804 }
4805 } // end of sample
4806 } // end of seg
4807
4808 // Norm factor for time:
4809 for(MInt i = 0; i < noSamples(); i++) {
4810 m_times[i] *= m_input2Aca.time;
4811 }
4812}
struct AcaSolver::ConversionFactors m_input2Aca

◆ checkNoSamplesPotencyOfTwo()

template<MInt nDim>
void AcaSolver< nDim >::checkNoSamplesPotencyOfTwo
private

Definition at line 4864 of file acasolver.cpp.

4864 {
4865 // Check if noSamples is a potency of 2 to see if FFT can be used
4866 MInt numSampl = noSamples();
4867 MInt prove = 1;
4868 m_FastFourier = false;
4869
4870 // if potency of 2: numSampl == 0; if not: numSampl == 1
4871 while(numSampl > 1) {
4872 numSampl /= 2;
4873 prove *= 2;
4874 }
4875 if(prove == noSamples()) {
4876 m_FastFourier = true;
4877 m_log << " >> NOTE: Number of samples is a potency of 2. Thus Fast Fourier Transform can "
4878 "be used, if not defined otherwise (transformationType = 0 for DFT)."
4879 << std::endl;
4880 } else { // prove != noSamples()
4881 m_FastFourier = false;
4883 m_log << " >> NOTE: Number of samples is not a potency of 2. Thus Fast Fourier Transform "
4884 "cannot be used, no matter what."
4885 << std::endl;
4886 }
4887}

◆ cleanUp()

template<MInt nDim>
virtual void AcaSolver< nDim >::cleanUp ( )
inlinevirtual

Implements Solver.

Definition at line 118 of file acasolver.h.

118{};

◆ combineSurfaceIntegrals()

template<MInt nDim>
void AcaSolver< nDim >::combineSurfaceIntegrals ( const MInt  globalObserverId,
MFloat *const  p_complexVariables 
)
private
Parameters
[in]globalObserverIdGlobal observer id
[in]p_complexVariablesOutput of complex p', length of 2*noSamples()

Definition at line 2203 of file acasolver.cpp.

2203 {
2204 TRACE();
2205 RECORD_TIMER_START(m_timers[Timers::CombineSurfaceIntegrals]);
2206
2207 // Data is stored in unconvenient way (globalObserverId, 0) so that Allreduce won't work. Put Data in linear
2208 // sequence --> Allreduce --> Back in the convenient data structure
2209 // (globalObserverId, 0)
2210
2211 // First: Copy all Observerdata to a databuffer
2212 // obsDataSize is noSamples, because we have imaginary and real part but only for half of samples
2213 // (all positive frequencies including zero)
2214 constexpr MInt noRealAndIm = 2;
2215 const MInt halfNoSamplesRealAndIm = (noSamples() / 2 + 1) * noRealAndIm;
2216 const MInt dataBuffSize = halfNoSamplesRealAndIm * 1.0;
2217 std::vector<MFloat> obsDataBuff(dataBuffSize, 0.0);
2218
2219 const MInt trgDomain = getObserverDomainId(globalObserverId);
2220 const MInt observerId = a_localObserverId(globalObserverId);
2221
2222 TERMM_IF_COND(trgDomain == domainId() && (observerId < 0 || observerId > noObservers()),
2223 "Error in observer partitioning!");
2224
2225 // The actual copying: Whole observer Data from observer "globalObserverId" to the position globalObserverId *
2226 // obsDataSize in databuffer
2227 std::copy_n(p_complexVariables, halfNoSamplesRealAndIm, obsDataBuff.data());
2228 // obsDataBuff now contains all complex pressure values of all observers in linear sequence
2229
2230 if(domainId() == trgDomain) {
2231 // Sums up all parts of the surface integral and distributes the results back to all processes.
2232 MPI_Reduce(MPI_IN_PLACE, obsDataBuff.data(), dataBuffSize, type_traits<MFloat>::mpiType(), MPI_SUM, trgDomain,
2233 mpiComm(), AT_, "MPI_IN_PLACE", "obsDataBuff");
2234 // obsDataBuff now contains the FWH-Integral value of each observer and each frequency in linear
2235 // sequence.
2236
2237 // Split the data buffer into the convenient data structure
2238 std::copy_n(obsDataBuff.data(), halfNoSamplesRealAndIm, &m_observerData.complexVariables(observerId, 0));
2239 } else {
2240 MPI_Reduce(obsDataBuff.data(), obsDataBuff.data(), dataBuffSize, type_traits<MFloat>::mpiType(), MPI_SUM, trgDomain,
2241 mpiComm(), AT_, "MPI_IN_PLACE", "obsDataBuff");
2242 }
2243
2244 // At first the segments were split up on processers. Each processes computed
2245 // the integral for all observers for his segments. Then all integral were
2246 // summed up. Now, all processes have the correct (local) observer data.
2247
2248 RECORD_TIMER_STOP(m_timers[Timers::CombineSurfaceIntegrals]);
2249}
MInt getObserverDomainId(const MInt globalObserverId)
Get domain id of (global) observer.
Definition: acasolver.h:177
MInt a_localObserverId(const MInt globalObserverId)
Return local observer id.
Definition: acasolver.h:155
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Reduce

◆ combineSurfaceIntegralsInTime()

template<MInt nDim>
void AcaSolver< nDim >::combineSurfaceIntegralsInTime ( const MInt  globalObserverId,
MFloat *const  p_perturbedFWH 
)
private

Definition at line 2253 of file acasolver.cpp.

2253 {
2254 TRACE();
2255
2256 // Data is stored in unconvenient way (globalObserverId, 0) so that Allreduce won't work. Put Data in linear
2257 // sequence --> Allreduce --> Back in the convenient data structure (globalObserverId, 0)
2258
2259 // First: Copy all Observerdata to a databuffer
2260 const MInt dataBuffSize = noSamples();
2261 std::vector<MFloat> obsDataBuff(dataBuffSize, 0.0);
2262
2263 const MInt trgDomain = getObserverDomainId(globalObserverId);
2264 const MInt observerId = a_localObserverId(globalObserverId);
2265
2266 TERMM_IF_COND(trgDomain == domainId() && (observerId < 0 || observerId > noObservers()),
2267 "Error in observer partitioning!");
2268
2269 // The actual copying: Whole observer Data from observer "globalObserverId" to
2270 // the position globalObserverId * obsDataSize in databuffer
2271 std::copy_n(p_perturbedFWH, dataBuffSize, obsDataBuff.data());
2272 // obsDataBuff now contains all complex pressure values of all observers in linear sequence
2273
2274 if(domainId() == trgDomain) {
2275 // Sums up all parts of the surface integral and distributes the results back to all processes.
2276 MPI_Reduce(MPI_IN_PLACE, obsDataBuff.data(), dataBuffSize, type_traits<MFloat>::mpiType(), MPI_SUM, trgDomain,
2277 mpiComm(), AT_, "MPI_IN_PLACE", "obsDataBuff");
2278 // obsDataBuff now contains the FWH-Integral value of each observer and each frequency in linear sequence.
2279
2280 // Split the data buffer into the convenient data structure
2281 std::copy_n(obsDataBuff.data(), dataBuffSize, &m_observerData.variables(observerId, 0));
2282 } else {
2283 MPI_Reduce(obsDataBuff.data(), obsDataBuff.data(), dataBuffSize, type_traits<MFloat>::mpiType(), MPI_SUM, trgDomain,
2284 mpiComm(), AT_, "MPI_IN_PLACE", "obsDataBuff");
2285 }
2286
2287 // At first the segments were split up on processers. Each processes computed
2288 // the integral for all observers for his segments. Then all integral were
2289 // summed up. Now, all processes have the correct (local) observer data.
2290}

◆ computeAccuracy()

template<MInt nDim>
void AcaSolver< nDim >::computeAccuracy
private

Definition at line 4892 of file acasolver.cpp.

4892 {
4893 TERMM(1, "TODO check this function");
4894 if(domainId() == 0) {
4895 std::cout << "8. Starting accuarcy calculation." << std::endl;
4896
4897 // These parameters have to be set
4898 // -------------------
4899 const MInt observer = globalNoObservers();
4900 MInt noSegs = 100;
4901 noSegs = Context::getSolverProperty<MFloat>("noSegments_" + std::to_string(0), m_solverId, AT_, 0);
4902 if(noSegs == 0) {
4903 noSegs = Context::getSolverProperty<MFloat>("noSegments_" + std::to_string(0), m_solverId, AT_, 1);
4904 }
4905
4906 MFloat box_size = 2.0 * 2;
4907 box_size = Context::getSolverProperty<MFloat>("surfaceCoordinates_" + std::to_string(0), m_solverId, AT_, 0);
4908 box_size = 2.0 * std::fabs(box_size);
4909 // --------------------
4910
4911 // Alternative expression: SamplePoints per Period even with flow
4912 MFloat noPeriods = 1.0;
4913 noPeriods = Context::getSolverProperty<MFloat>("noPeriods", m_solverId, AT_, &noPeriods);
4914
4915 MFloat omega_factor = 4.0;
4916 omega_factor = Context::getSolverProperty<MFloat>("omega_factor", m_solverId, AT_, &omega_factor);
4917
4918 MFloat Delta_Seg = box_size / noSegs;
4919 if constexpr(nDim == 3) {
4920 Delta_Seg *= Delta_Seg;
4921 }
4922
4923 // Wave length lambda
4925 m_lambdaMach = 2.0 * (1.0 - m_Ma) / m_omega_factor;
4926
4927 // minimal resolution of one period according to the thesis.
4928 const MFloat R_min = noSamples() * m_lambdaMach / (noPeriods * m_lambdaZero);
4929 const MFloat Z = Delta_Seg / R_min;
4930 const MFloat Y = Delta_Seg / m_lambdaMach;
4931
4932 // Read in the analytic solution for even periods to be able to compare with uneven periods
4933 std::vector<MFloat> Analytic_EvenPeriods(globalNoObservers() * noSamples() / 2 * 5, 0.0);
4934 std::vector<MFloat> Analytic_EvenPeriods_Amplitude(globalNoObservers() * noSamples() / 2, 0.0);
4935 std::vector<MFloat> Analytic_EvenPeriods_Frequencies(globalNoObservers() * noSamples() / 2, 0.0);
4936 std::vector<MFloat> RMS_EvenPeriods(globalNoObservers(), 0.0);
4937
4938 const MInt EP_Samples = 64;
4939 if(noSamples() == EP_Samples) {
4940 std::ifstream file;
4941 MString line;
4942 MString Name = "./test/AnalyticSolution_ForEvenPeriods.dat";
4943 file.open(Name, std::ios::in);
4944 MInt count = 0;
4945 MFloat i1, i2, i3, i4, i5;
4946 if(file.is_open()) {
4947 while(getline(file, line)) {
4948 std::stringstream linebuffer(line);
4949 linebuffer >> i1 >> i2 >> i3 >> i4 >> i5;
4950 Analytic_EvenPeriods[5 * count] = i1;
4951 Analytic_EvenPeriods[5 * count + 1] = i2;
4952 Analytic_EvenPeriods[5 * count + 2] = i3;
4953 Analytic_EvenPeriods[5 * count + 3] = i4;
4954 Analytic_EvenPeriods[5 * count + 4] = i5;
4955
4956 Analytic_EvenPeriods_Amplitude[count] = i4;
4957 Analytic_EvenPeriods_Frequencies[count] = i1;
4958 count += 1;
4959 }
4960 } else {
4961 std::cerr << "Fehler beim Öffnen der Datei: " << Name << "." << std::endl;
4962 }
4963
4964 std::ifstream file1;
4965 MString line1;
4966 MString Name1 = "./test/RMSEvenPeriods.dat";
4967 file1.open(Name1, std::ios::in);
4968 MInt count1 = 0;
4969 MFloat i_1, i_2;
4970 if(file1.is_open()) {
4971 while(getline(file1, line1)) {
4972 std::stringstream linebuffer(line1);
4973 linebuffer >> i_1 >> i_2;
4974 RMS_EvenPeriods[count1] = i_2;
4975 count1 += 1;
4976 }
4977 } else {
4978 std::cerr << "Fehler beim Öffnen der Datei: " << Name1 << "." << std::endl;
4979 }
4980 }
4981 // RMS PRESSURE
4982 std::vector<MFloat> p_rms(globalNoObservers(), 0.0);
4983
4984 for(MInt obs = 0; obs < globalNoObservers(); obs++) {
4985 for(MInt t = 0; t < noSamples(); t++) {
4986 p_rms[obs] += m_observerData.variables(obs, 0, t) * m_observerData.variables(obs, 0, t);
4987 }
4988 p_rms[obs] = sqrt(p_rms[obs] / noSamples());
4989 }
4990
4991 // Quality (Variance) check
4992 MFloat max_diff = 0.0;
4993 MFloat max_diff_2 = 0.0;
4994 MFloat diff_normalized = 0.0;
4995 MFloat diff_2_normalized = 0.0;
4996 MFloat sum_diff_sq = 0.0;
4997 MFloat sum_diff_2_sq = 0.0;
4998 MFloat sum_analytic_sq = 0.0;
4999 MFloat sum_a_ep_sq = 0.0;
5000 std::vector<MFloat> diff(observer, 0.0);
5001 std::vector<MFloat> diff_2(observer, 0.0);
5002 for(MInt i = 0; i < observer; i++) {
5003 diff[i] = std::fabs(m_rmsP_Analytic[i] - p_rms[i]);
5004 sum_diff_sq += diff[i] * diff[i];
5005 sum_analytic_sq += m_rmsP_Analytic[i];
5006 diff_normalized = diff[i] / m_rmsP_Analytic[i] * 100;
5007
5008 // In case of uneven periods
5009 if(noSamples() == EP_Samples) {
5010 diff_2[i] = std::fabs(RMS_EvenPeriods[i] - p_rms[i]);
5011 sum_diff_2_sq += diff_2[i] * diff_2[i];
5012 sum_a_ep_sq += RMS_EvenPeriods[i];
5013 diff_2_normalized = diff_2[i] / RMS_EvenPeriods[i] * 100;
5014 }
5015 if(diff_normalized >= max_diff) {
5016 if(m_rmsP_Analytic[i] > 10e-13) {
5017 max_diff = diff_normalized; // [%]
5018 }
5019 if(EP_Samples == 64) {
5020 max_diff_2 = diff_2_normalized; //[%]
5021 }
5022 }
5023 }
5024 const MFloat value_top = sqrt(sum_diff_sq / globalNoObservers());
5025 const MFloat value_bot = sum_analytic_sq / globalNoObservers();
5026 const MFloat Q_C = 100 * value_top / value_bot; // [%]
5027
5028 // In case of uneven periods
5029 MFloat Q_C_UnevenPeriods = 0.0;
5030 if(noSamples() == EP_Samples) {
5031 const MFloat value_top_UP = sqrt(sum_diff_2_sq / globalNoObservers());
5032 const MFloat value_bot_UP = sum_a_ep_sq / globalNoObservers();
5033 Q_C_UnevenPeriods = 100 * value_top_UP / value_bot_UP;
5034 }
5035
5036 // Frequency, Amplitude comparison for all observers
5037 std::vector<MFloat> diff_Ampl(globalNoObservers() * noSamples(), 0.0);
5038 std::vector<MFloat> max_Ampl(globalNoObservers(), 0.0);
5039 std::vector<MFloat> max_Ampl_2(globalNoObservers(), 0.0);
5040 std::vector<MFloat> max_Ampl_a(globalNoObservers(), 0.0);
5041 std::vector<MFloat> max_Ampl_A_EvenPeriods(globalNoObservers(), 0.0);
5042 std::vector<MFloat> max_Ampl_Diff(globalNoObservers(), 0.0);
5043 std::vector<MFloat> max_Ampl_Diff_2(globalNoObservers(), 0.0);
5044 std::vector<MFloat> max_Ampl_Diff_normalized(globalNoObservers(), 0.0);
5045 std::vector<MFloat> max_Ampl_Diff_normalized_2(globalNoObservers(), 0.0);
5046 std::vector<MFloat> freq_At_Max_Ampl(globalNoObservers(), 0.0);
5047 std::vector<MFloat> freq_At_Max_Ampl_2(globalNoObservers(), 0.0);
5048 std::vector<MFloat> freq_At_Max_Ampl_a(globalNoObservers(), 0.0);
5049 std::vector<MFloat> freq_At_Max_Ampl_A_EvenPeriods(globalNoObservers(), 0.0);
5050 std::vector<MFloat> freq_Diff(globalNoObservers(), 0.0);
5051 std::vector<MFloat> freq_Diff_2(globalNoObservers(), 0.0);
5052 std::vector<MFloat> freq_Diff_normalized(globalNoObservers(), 0.0);
5053 std::vector<MFloat> freq_Diff_normalized_2(globalNoObservers(), 0.0);
5054 std::vector<MFloat> mean_Ampl_analytic(globalNoObservers(), 0.0);
5055 std::vector<MFloat> sum_Diff_Amplitudes_UnevenPeriods(globalNoObservers(), 0.0);
5056 std::vector<MFloat> SideLobes(globalNoObservers(), 0.0);
5057 MFloat sum_max_Ampl_Diff_normalized = 0.0;
5058 MFloat sum_freq_Diff_normalized = 0.0;
5059 MFloat sum_max_Ampl_Diff_normalized_2 = 0.0;
5060 MFloat sum_freq_Diff_normalized_2 = 0.0;
5061 MFloat sum_SideLobes = 0.0;
5062 MFloat Amplitude_EvenPeriods = 0.0;
5063 for(MInt obs = 0; obs < globalNoObservers(); obs++) {
5064 for(MInt i = 1; i < noSamples() / 2 + 1; i++) {
5065 const MFloat real_c = m_observerData.complexVariables(obs, 0, i, 0);
5066 const MFloat imag_c = m_observerData.complexVariables(obs, 0, i, 1);
5067 const MFloat real_a = m_Analyticfreq[obs * noSamples() * 2 + 2 * i];
5068 const MFloat imag_a = m_Analyticfreq[obs * noSamples() * 2 + 2 * i + 1];
5069 const MFloat Amplitude_c = 2 * sqrt(real_c * real_c + imag_c * imag_c);
5070 const MFloat Amplitude_a = 2 * sqrt(real_a * real_a + imag_a * imag_a);
5071 // Comparison with even periods in case uneven periods are used
5072 if(noSamples() == EP_Samples) {
5073 Amplitude_EvenPeriods = Analytic_EvenPeriods_Amplitude[obs * noSamples() / 2 + (i - 1)];
5074
5075 // Get Frequency at which the analytic source for even periods oscillates
5076 if(Amplitude_EvenPeriods > max_Ampl_A_EvenPeriods[obs]) {
5077 freq_At_Max_Ampl_A_EvenPeriods[obs] = Analytic_EvenPeriods_Frequencies[obs * noSamples() / 2 + (i - 1)];
5078 max_Ampl_A_EvenPeriods[obs] = Amplitude_EvenPeriods;
5079 }
5080 }
5081
5082 // Get Frequency at which analytic source oscillates
5083 if(Amplitude_a > max_Ampl_a[obs]) {
5084 freq_At_Max_Ampl_a[obs] = m_frequencies[i];
5085 max_Ampl_a[obs] = Amplitude_a;
5086 }
5087
5088 // Get max Amplitude computed and its frequency
5089 if(Amplitude_c > max_Ampl[obs]) {
5090 freq_At_Max_Ampl[obs] = m_frequencies[i];
5091 max_Ampl[obs] = Amplitude_c;
5092 }
5093
5094 // Side lobes
5095 SideLobes[obs] += std::fabs(Amplitude_EvenPeriods - Amplitude_c);
5096 }
5097 // Normalize the maximum difference in amplitude and frequency with the maximum analytical
5098 // ampl. and freq. Index 2 is for uneven Periods comparison
5099 max_Ampl_Diff[obs] = std::fabs(max_Ampl_a[obs] - max_Ampl[obs]);
5100 freq_Diff[obs] = std::fabs(freq_At_Max_Ampl[obs] - freq_At_Max_Ampl_a[obs]);
5101
5102 max_Ampl_Diff_normalized[obs] = max_Ampl_Diff[obs] / max_Ampl_a[obs];
5103 freq_Diff_normalized[obs] = freq_Diff[obs] / freq_At_Max_Ampl_a[obs];
5104
5105 sum_max_Ampl_Diff_normalized += max_Ampl_Diff_normalized[obs];
5106 sum_freq_Diff_normalized += freq_Diff_normalized[obs];
5107
5108 if(noSamples() == EP_Samples) {
5109 max_Ampl_Diff_2[obs] = std::fabs(max_Ampl_A_EvenPeriods[obs] - max_Ampl[obs]);
5110 freq_Diff_2[obs] = std::fabs(freq_At_Max_Ampl[obs] - freq_At_Max_Ampl_A_EvenPeriods[obs]);
5111 sum_SideLobes += (SideLobes[obs] / (noSamples() / 2));
5112
5113 max_Ampl_Diff_normalized_2[obs] = max_Ampl_Diff_2[obs] / max_Ampl_A_EvenPeriods[obs];
5114 freq_Diff_normalized_2[obs] = freq_Diff_2[obs] / freq_At_Max_Ampl_A_EvenPeriods[obs];
5115
5116 // In case of uneven and even periods comparison
5117 sum_max_Ampl_Diff_normalized_2 += max_Ampl_Diff_normalized_2[obs];
5118 sum_freq_Diff_normalized_2 += freq_Diff_normalized_2[obs];
5119 }
5120 }
5121 const MFloat Ampl_aver_Diff = 100 * sum_max_Ampl_Diff_normalized / globalNoObservers(); // [%]
5122 const MFloat Freq_aver_Diff = 100 * sum_freq_Diff_normalized / globalNoObservers(); // [%]
5123
5124 // In case of uneven and even periods comparison
5125 MFloat Side_Lobes = 0.0;
5126 MFloat Freq_aver_Diff_UnevenPeriods = 0.0;
5127 MFloat Ampl_aver_Diff_UnevenPeriods = 0.0;
5128 if(noSamples() == EP_Samples) {
5129 Ampl_aver_Diff_UnevenPeriods = 100 * sum_max_Ampl_Diff_normalized_2 / globalNoObservers(); //[%]
5130 Freq_aver_Diff_UnevenPeriods = 100 * sum_freq_Diff_normalized_2 / globalNoObservers(); //[%]
5131 Side_Lobes = 100 * sum_SideLobes / globalNoObservers(); //[%]
5132 // Those minor deviations are due to the writing out in a file and re-reading it again
5133 // (Analytic Even Periods). Thus, they match perfectly but a deviation is falsly shown
5134 if(Freq_aver_Diff_UnevenPeriods < 1e-10) {
5135 Freq_aver_Diff_UnevenPeriods = 0.0;
5136 }
5137 }
5138
5139 // OUTPUT OF max Amplitude at given frequencie
5140 MString fileFreq = "./FreqComparison/maxFreqCompare_";
5141 fileFreq += std::to_string(noSegs);
5142 fileFreq += ".dat";
5143 std::ofstream outfile;
5144 outfile.open(fileFreq);
5145 outfile << Y << " " << Freq_aver_Diff << " " << Ampl_aver_Diff << " " << Side_Lobes << std::endl;
5146 outfile.close();
5147
5148 // Freq for samples
5149 MString fileF = "./FreqComparison/maxFreqCompareSamples_";
5150 fileF += std::to_string(noSamples());
5151 fileF += ".dat";
5152 outfile.open(fileF);
5153 outfile << R_min << " " << Freq_aver_Diff << " " << Ampl_aver_Diff << " " << Side_Lobes << std::endl;
5154
5155 outfile.close();
5156
5157 if(noSamples() == EP_Samples) {
5158 // Freq for periods
5159 MString fileFr = "./FreqComparison/maxFreqComparePeriods_";
5160 fileFr += std::to_string(noPeriods);
5161 fileFr += ".dat";
5162 outfile.open(fileFr);
5163 outfile << noPeriods << " " << Freq_aver_Diff_UnevenPeriods << " " << Ampl_aver_Diff_UnevenPeriods << " "
5164 << Side_Lobes << " " << Ampl_aver_Diff << std::endl;
5165 outfile.close();
5166 }
5167
5168 // OUTPUT IF ONE VARIES NUMBER OF SEGMENTS
5169 MString ofile = "./Diff_seg/accuracy_";
5170 ofile += std::to_string(noSegs);
5171 ofile += ".dat";
5172 outfile.open(ofile);
5173 outfile << Y << " " << Q_C << " " << max_diff << " " << Z << " " << Side_Lobes << std::endl;
5174 outfile.close();
5175
5176 // OUTPUT IF ONE VARIES NUMBER OF SAMPLES
5177 MString fileName = "./Diff_Samples/accuracy_";
5178 fileName += std::to_string(noSamples());
5179 fileName += ".dat";
5180 outfile.open(fileName);
5181 outfile << R_min << " " << Q_C << " " << max_diff << " " << Side_Lobes << std::endl;
5182 outfile.close();
5183
5184 if(noSamples() == EP_Samples) {
5185 // OUTPUT IF ONE VARIES NUMBER OF SAMPLES
5186 MString fileN = "./Diff_Periods/accuracy_";
5187 fileN += std::to_string(noPeriods);
5188 fileN += ".dat";
5189 outfile.open(fileN);
5190 outfile << noPeriods << " " << Q_C_UnevenPeriods << " " << max_diff_2 << " " << Side_Lobes << std::endl;
5191 outfile.close();
5192 }
5193
5194 // OUTPUT IF ONE VARIES NUMBER OF SAMPLES
5195 MString fileNa = "./Diff_omega/accuracy_";
5196 fileNa += std::to_string(omega_factor);
5197 fileNa += ".dat";
5198 outfile.open(fileNa);
5199 outfile << omega_factor << " " << Q_C << " " << max_diff << " " << Side_Lobes << std::endl;
5200 outfile.close();
5201
5202 std::cout << "8. Accuarcy calculation finished." << std::endl;
5203 }
5204}
MFloat m_lambdaZero
Wave length lambda.
Definition: acasolver.h:404
MFloat m_Ma
Mach number.
Definition: acasolver.h:423
MFloat m_lambdaMach
Definition: acasolver.h:405
std::vector< MFloat > m_rmsP_Analytic
Analytic rms pressure for accuracy function.
Definition: acasolver.h:415
std::vector< MFloat > m_Analyticfreq
Analytic Fourier Transformation, also used for Validation.
Definition: acasolver.h:412
MFloat m_omega_factor
Omega factor.
Definition: acasolver.h:401
const MInt m_solverId
a unique solver identifier
Definition: solver.h:90
std::istream & getline(std::istream &input, std::string &line)
Definition: cpptoml.h:1519

◆ computeDt()

template<MInt nDim>
void AcaSolver< nDim >::computeDt
private

Definition at line 4845 of file acasolver.cpp.

4845 {
4846 // Compute time step size
4847 m_dt = (m_times[noSamples() - 1] - m_times[0]) / (static_cast<MFloat>(noSamples() - 1));
4848
4849 // Check for equidistant timesteps - necessary for the computation!
4850 for(MInt i = 1; i < noSamples(); i++) {
4851 const MFloat delta = m_times[i] - m_times[i - 1];
4852 const MFloat relErr = std::fabs(m_dt - delta) / m_dt;
4853 if(relErr > 1e-10) {
4854 std::ostringstream err;
4855 err << std::setprecision(12) << std::scientific << "Error: time step size mismatch; m_dt = " << m_dt
4856 << "; delta = " << delta << "; relErr = " << relErr << "; i = " << i << "; times[i] = " << m_times[i]
4857 << "; times[i-1] = " << m_times[i - 1];
4858 TERMM(1, err.str());
4859 }
4860 }
4861}

◆ DiscreteFourierTransform()

template<MInt nDim>
void AcaSolver< nDim >::DiscreteFourierTransform ( MFloat dataArray,
const MInt  size,
const MInt  dir,
MFloat result,
const MBool  inPlace 
)
private
Parameters
dataArrayPointer to complex data array.
sizeSize of the complex data array (number of samples).
dirDirection of transformation: 1=forward; -1=backward.
resultOptional storage for transformed data, used if inPlace==false.
inPlaceDetermines if result overwrites the input data or stored in result array.

Definition at line 1500 of file acasolver.cpp.

1501 {
1502 TRACE();
1503 const MFloat sizeF = static_cast<MFloat>(size);
1504 const MInt size2 = 2 * size;
1505 MFloat* resultPtr = nullptr;
1506 std::vector<MFloat> resultArray;
1507
1508 if(inPlace) {
1509 resultArray.resize(size2); // Temporary solution storage
1510 resultPtr = &resultArray[0];
1511 } else {
1512 ASSERT(result != nullptr, "Pointer to result storage is nullptr.");
1513 resultPtr = result; // Store solution in provided storage
1514 }
1515
1516 if(dir == 1) { // FOURIER FORWARD
1517 const MFloat con = 2.0 * PI / sizeF;
1518 for(MInt k = 0; k < size; k++) {
1519 for(MInt i = 0; i < size; i++) {
1520 // cos(-a) = cos(a) and sin(-a) = -sin(a)
1521 // Actual Discrete Fourier Transform
1522 resultPtr[2 * k] += dataArray[2 * i] * cos(k * con * i) + dataArray[2 * i + 1] * sin(k * con * i);
1523 resultPtr[2 * k + 1] += -1.0 * dataArray[2 * i] * sin(k * con * i) + dataArray[2 * i + 1] * cos(k * con * i);
1524 }
1525 resultPtr[2 * k] /= sizeF;
1526 resultPtr[2 * k + 1] /= sizeF;
1527 }
1528 } else if(dir == -1) { // FOURIER BACKWARD
1529 for(MInt t = 0; t < size; t++) {
1530 const MFloat arg = 2.0 * PI * t / sizeF;
1531 for(MInt k = 0; k < size; k++) {
1532 resultPtr[2 * t] += dataArray[2 * k] * cos(arg * k) - dataArray[2 * k + 1] * sin(arg * k);
1533 resultPtr[2 * t + 1] += dataArray[2 * k] * sin(arg * k) + dataArray[2 * k + 1] * cos(arg * k);
1534 }
1535 }
1536 } else {
1537 TERMM(1, "Please insert 1 for forward or -1 for backward");
1538 }
1539
1540 if(inPlace) {
1541 // Copy results back into dataArray overwriting the input data
1542 std::copy_n(&resultPtr[0], size2, &dataArray[0]);
1543 }
1544}

◆ distributeObservers()

template<MInt nDim>
void AcaSolver< nDim >::distributeObservers
private

Evenly distribute observers on all ranks.

Definition at line 2333 of file acasolver.cpp.

2333 {
2334 TRACE();
2335 const MInt minNoObsPerDomain = globalNoObservers() / noDomains();
2336 const MInt remainderObs = globalNoObservers() % noDomains();
2337 if(domainId() < remainderObs) {
2338 m_noObservers = minNoObsPerDomain + 1;
2339 m_offsetObserver = domainId() * (minNoObsPerDomain + 1);
2340 } else {
2341 m_noObservers = minNoObsPerDomain;
2342 m_offsetObserver = domainId() * minNoObsPerDomain + remainderObs;
2343 }
2344}
virtual MInt noDomains() const
Definition: solver.h:387

◆ FastFourierTransform()

template<MInt nDim>
void AcaSolver< nDim >::FastFourierTransform ( MFloat dataArray,
const MInt  size,
const MInt  dir,
MFloat result,
const MBool  inPlace 
)
private

Fast Fourier transformation.

Reference: 'Numerical Recipes in C', Cambridge, p. 507 ff.

Parameters
dataArrayPointer to complex data array.
sizeSize of the complex data array (number of samples).
dirDirection of transformation: 1=forward; -1=backward.
resultOptional storage for transformed data, used if inPlace==false.
inPlaceDetermines if result overwrites the input data or stored in result array.

Definition at line 1411 of file acasolver.cpp.

1412 {
1413 TRACE();
1414 TERMM_IF_NOT_COND(dir == 1 || dir == -1, "Invalid direction");
1415 TERMM_IF_NOT_COND(size % 2 == 0, "FFT: not a multiple of 2 samples.");
1416
1417 const MFloat isign = (dir == 1) ? -1.0 : 1.0;
1418 const MBool dim = (dir == 1) ? true : false;
1419 const MInt size2 = 2 * size; // full array size (real+imag)
1420
1421 // Set pointer to result storage
1422 MFloat* const data = (inPlace) ? dataArray : result;
1423 // Copy input data if not performing transform in-place (overwriting input)
1424 if(!inPlace) {
1425 ASSERT(result != nullptr, "Pointer to result storage is nullptr.");
1426 std::copy_n(&dataArray[0], size2, result);
1427 }
1428
1429#define SWAP(a, b) \
1430 rtemp = (a); \
1431 (a) = (b); \
1432 (b) = rtemp
1433 // Bit reversing: Reorder by inverse bit notation, e.g. first number: 0000 --> 0000, second
1434 // number: 0001 -> 1000
1435 const MInt nn = size;
1436 MInt n = nn << 1;
1437 MInt m;
1438 MFloat rtemp;
1439 MInt j = 1;
1440 for(MInt i = 1; i < n; i += 2) {
1441 if(j > i) {
1442 SWAP(data[j - 1], data[i - 1]);
1443 SWAP(data[j], data[i]);
1444 }
1445 m = nn;
1446 while(m >= 2 && j > m) {
1447 j -= m;
1448 m >>= 1;
1449 }
1450 j += m;
1451 }
1452
1453 // Fourier Transformation (Danielson-Lanczos)
1454 MUlong istep, p, k, i;
1455 MFloat wtemp, wr, wpr, wpi, wi, theta, tempr, tempi;
1456 const MUlong nLong = static_cast<MUlong>(size2);
1457 MUlong mmax = 2;
1458 while(nLong > mmax) {
1459 istep = mmax << 1;
1460 theta = isign * (6.28318530717959 / mmax);
1461 wtemp = sin(0.5 * theta);
1462 wpr = -2.0 * wtemp * wtemp;
1463 wpi = sin(theta);
1464 wr = 1.0;
1465 wi = 0.0;
1466 for(p = 1; p < mmax; p += 2) {
1467 for(i = p; i <= nLong; i += istep) {
1468 k = i + mmax;
1469 tempr = wr * data[k - 1] - wi * data[k];
1470 tempi = wr * data[k] + wi * data[k - 1];
1471 data[k - 1] = data[i - 1] - tempr;
1472 data[k] = data[i] - tempi;
1473 data[i - 1] += tempr;
1474 data[i] += tempi;
1475 }
1476 wr = (wtemp = wr) * wpr - wi * wpi + wr;
1477 wi = wi * wpr + wtemp * wpi + wi;
1478 }
1479 mmax = istep;
1480 }
1481
1482 // Dimensionierung
1483 if(dim) {
1484 for(MInt z = 0; z < size2; z++) {
1485 data[z] /= size;
1486 }
1487 }
1488}
void SWAP(T &a, T &b)
Definition: kdtree.h:21
bool MBool
Definition: maiatypes.h:58
uint64_t MUlong
Definition: maiatypes.h:65

◆ finalizeInitSolver()

template<MInt nDim>
void AcaSolver< nDim >::finalizeInitSolver ( )
inlineoverridevirtual

Implements Solver.

Definition at line 106 of file acasolver.h.

106{};

◆ genDipoleAnalytic2D()

template<MInt nDim>
void AcaSolver< nDim >::genDipoleAnalytic2D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

2D analytical dipole generation

Definition at line 4160 of file acasolver.cpp.

4160 {
4161 MFloat x = coord[0];
4162 MFloat y = coord[1];
4164
4165 const MFloat omega = param.omega;
4166 const MFloat c0 = 1.0; // by definition
4167 const MFloat rho0 = param.rho0;
4168 const MFloat p0 = rho0 * c0 * c0 / m_gamma;
4169 const MFloat beta = param.beta;
4170 const MFloat G = param.amplitude;
4171 const MFloat u0 = param.Ma * c0;
4172 const MFloat mach = param.Ma;
4173
4174 // Precompute time constant values/factors
4175 const MFloat beta2 = (beta * beta);
4176 const MFloat fbeta2 = 1 / beta2;
4177
4178 MFloat k = omega / c0;
4179
4180 const MFloat d = sqrt(x * x + beta2 * y * y);
4181 const MFloat dargdx = mach * k * fbeta2;
4182 const MFloat argHankel = k * d * fbeta2;
4183 const MFloat dHdx = k * x * fbeta2 / d;
4184 const MFloat dHdxdx = k * y * y / (d * d * d);
4185 const MFloat dHdxdy = -1.0 * k * x * y / (d * d * d);
4186 const MFloat dHdy = k * y / d;
4187 const MFloat C1 = -1.0 * mach * G * k / (4.0 * beta2 * beta);
4188 const MFloat C2 = G / (4.0 * beta);
4189
4190 const MFloat J0 = j0(argHankel);
4191 const MFloat J1 = j1(argHankel);
4192 const MFloat dJ1 = J0 - (1 / argHankel) * J1;
4193
4194 const MFloat Y0 = y0(argHankel);
4195 const MFloat Y1 = y1(argHankel);
4196 const MFloat dY1 = Y0 - (1 / argHankel) * Y1;
4197
4198 for(MInt sample = 0; sample < noSamples(); sample++) {
4199 const MFloat time = sample * m_dt;
4200 const MFloat arg = omega * time + mach * k * x * fbeta2;
4201
4202 const MFloat cosarg = cos(arg);
4203 const MFloat sinarg = sin(arg);
4204
4205 const MFloat dPhidt =
4206 C1 * omega * (-1.0 * sinarg * J0 + cosarg * Y0) + C2 * dHdx * omega * (cosarg * J1 + sinarg * Y1);
4207 const MFloat dPhidx = -1.0 * C1 * (dargdx * (sinarg * J0 - cosarg * Y0) + dHdx * (cosarg * J1 + sinarg * Y1))
4208 + C2
4209 * (dHdxdx * (sinarg * J1 - cosarg * Y1) + dHdx * dargdx * (cosarg * J1 + sinarg * Y1)
4210 + dHdx * dHdx * (sinarg * dJ1 - cosarg * dY1));
4211
4212 const MFloat dPhidy = -1.0 * C1 * dHdy * (cosarg * J1 + sinarg * Y1)
4213 + C2 * (dHdxdy * (sinarg * J1 - cosarg * Y1) + dHdx * dHdy * (sinarg * dJ1 - cosarg * dY1));
4214 const MFloat pp = -1.0 * rho0 * (dPhidt + u0 * dPhidx);
4215
4216 if(param.perturbed) {
4217 vars.u[sample] = dPhidx;
4218 vars.v[sample] = dPhidy;
4219 vars.p[sample] = pp;
4220 } else {
4221 vars.u[sample] = dPhidx + u0;
4222 vars.v[sample] = dPhidy;
4223 vars.p[sample] = pp + p0;
4224 vars.rho[sample] = rho0 + pp / (c0 * c0);
4225 }
4226 transformBackToOriginalCoordinate2D(&vars.u[sample], &vars.v[sample]);
4227 }
4228}
MFloat time() const override
Return the time.
Definition: acasolver.h:109
void transformBackToOriginalCoordinate2D(MFloat *const fX, MFloat *const fY)
Definition: acasolver.cpp:2020
void transformCoordinatesToFlowDirection2D(MFloat *const fX, MFloat *const fY)
Coordinate transformation.
Definition: acasolver.cpp:1994

◆ genDipoleAnalytic3D()

template<MInt nDim>
void AcaSolver< nDim >::genDipoleAnalytic3D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

Definition at line 4233 of file acasolver.cpp.

4233 {
4234 MFloat x = coord[0];
4235 MFloat y = coord[1];
4236 MFloat z = coord[2];
4238
4239 const MFloat omega = param.omega;
4240 const MFloat c0 = 1.0; // by definition
4241 const MFloat rho0 = param.rho0;
4242 const MFloat p0 = rho0 * c0 * c0 / m_gamma;
4243 const MFloat beta = param.beta;
4244 const MFloat amplitude = param.amplitude;
4245 const MFloat u0 = param.Ma * c0;
4246 const MFloat mach = param.Ma;
4247
4248 MFloat k = omega / c0;
4249
4250 const MFloat beta2 = beta * beta;
4251 const MFloat fbeta2 = 1 / beta2;
4252 const MFloat d = sqrt(x * x + beta * beta * (y * y + z * z));
4253 const MFloat d2 = d * d;
4254 const MFloat fd2 = 1 / d2;
4255 const MFloat fd3 = 1 / (d2 * d);
4256 const MFloat C1 = amplitude / (4 * PI);
4257 const MFloat C2 = k * fbeta2;
4258
4259 const MFloat P1 = fd3 - 3 * x * x * fd2 * fd3;
4260 const MFloat P2 = 1 * fd2 - 2 * x * x * fd2 * fd2;
4261 const MFloat P3 = -1.0 * x * fd3;
4262
4263 const MFloat dargdx = -1.0 * C2 * (x / d - mach);
4264 const MFloat dargdy = -1.0 * k * y / d;
4265 const MFloat dargdz = -1.0 * k * z / d;
4266
4267 for(MInt sample = 0; sample < noSamples(); sample++) {
4268 // Note: adapted from acoupot3d/acou_pot.cpp::calc_p/ux/uy/uz_analytic()
4269 const MFloat time = sample * m_dt;
4270 const MFloat arg = omega * time - k * (d - mach * x) * fbeta2;
4271
4272 const MFloat cosarg = cos(arg);
4273 const MFloat sinarg = sin(arg);
4274
4275 const MFloat dPhidt =
4276 C1 * omega * fd3 * x * sinarg + C1 * omega * fd2 * x * C2 * cosarg - C1 * omega * C2 * (mach / d) * cosarg;
4277 const MFloat dPhidx = -1.0 * C1 * P1 * cosarg + C1 * x * fd3 * dargdx * sinarg + C1 * P2 * C2 * sinarg
4278 + C1 * x * fd2 * C2 * dargdx * cosarg - C1 * C2 * P3 * mach * sinarg
4279 - C1 * C2 * (mach / d) * dargdx * cosarg;
4280 const MFloat dPhidy = C1 * x * 3 * y * beta2 * fd3 * fd2 * cosarg + C1 * x * fd3 * dargdy * sinarg
4281 - C1 * x * C2 * 2 * y * beta2 * fd2 * fd2 * sinarg + C1 * x * C2 * fd2 * dargdy * cosarg
4282 + C1 * C2 * y * beta2 * mach * fd3 * sinarg - C1 * C2 * (mach / d) * dargdy * cosarg;
4283 const MFloat dPhidz = C1 * x * 3 * z * beta2 * fd3 * fd2 * cosarg + C1 * x * fd3 * dargdz * sinarg
4284 - C1 * x * C2 * 2 * z * beta2 * fd2 * fd2 * sinarg + C1 * x * C2 * fd2 * dargdz * cosarg
4285 + C1 * C2 * z * beta2 * mach * fd3 * sinarg - C1 * C2 * (mach / d) * dargdz * cosarg;
4286 const MFloat pp = -1.0 * rho0 * (dPhidt + u0 * dPhidx);
4287
4288 if(param.perturbed) {
4289 vars.u[sample] = dPhidx;
4290 vars.v[sample] = dPhidy;
4291 vars.w[sample] = dPhidz;
4292 vars.p[sample] = pp;
4293 } else {
4294 vars.u[sample] = dPhidx + u0;
4295 vars.v[sample] = dPhidy;
4296 vars.w[sample] = dPhidz;
4297 vars.p[sample] = pp + p0;
4298 vars.rho[sample] = rho0 + pp / (c0 * c0);
4299 }
4300 transformBackToOriginalCoordinate3D(&vars.u[sample], &vars.v[sample], &vars.w[sample]);
4301 }
4302}
void transformBackToOriginalCoordinate3D(MFloat *const fX, MFloat *const fY, MFloat *const fZ)
Definition: acasolver.cpp:2033

◆ generateSurfaceCircle()

template<MInt nDim>
void AcaSolver< nDim >::generateSurfaceCircle ( const MInt  sId)
private

Definition at line 3853 of file acasolver.cpp.

3853 {
3854 TRACE();
3855
3856 // Weighting factor for surface averaging
3857 const MFloat weight = m_surfaceWeightingFactor[sId];
3858
3859 if constexpr(nDim != 2) {
3860 TERMM(1, "Only implemented in 2D.");
3861 }
3862
3863 // TODO labels:ACA Fix this
3864 TERMM(1, "The 2D implementation is not tested and seems not to work properly.");
3865
3866 // Creating Circle with radius and number of Elements
3868 totalNoSurfaceElements = Context::getSolverProperty<MInt>("noSegments_" + std::to_string(m_surfaceIds[sId]),
3870
3871 MFloat radius = 1.0;
3872 radius = Context::getSolverProperty<MFloat>("radius", m_solverId, AT_, &radius);
3873
3874 const MFloat step_rad = 2 * PI / static_cast<MFloat>(totalNoSurfaceElements);
3875
3876 std::vector<MFloat> surfaceNormal(2, 0.0);
3877 const MInt surfaceOffset = localSurfaceOffset(sId);
3878 for(MInt i = 0; i < m_noSurfaceElements[sId]; i++) {
3879 const MInt id = surfaceOffset + i;
3880 // Add a new surface element
3882 // Check that the total size of m_surfaceData is correct
3883 TERMM_IF_NOT_COND(m_surfaceData.size() == id + 1, "m_surfaceData size mismatch.");
3884
3885 // First surface point
3886 const MFloat p1_x = radius * cos(i * step_rad);
3887 const MFloat p1_y = radius * sin(i * step_rad);
3888
3889 // Second surface point
3890 const MFloat p2_x = radius * cos((i + 1) * step_rad);
3891 const MFloat p2_y = radius * sin((i + 1) * step_rad);
3892
3893 // Segment center
3894 const MFloat xcenter = 0.5 * (p2_x + p1_x);
3895 const MFloat ycenter = 0.5 * (p2_y + p1_y);
3896
3897 // Determine segment length
3898 const MFloat dx = (p2_x - p1_x);
3899 const MFloat dy = (p2_y - p1_y);
3900 const MFloat delta_segment = sqrt(dx * dx + dy * dy);
3901
3902 // Store segment center coordinates
3903 MFloat* surfCoordinates = &m_surfaceData.surfaceCoordinates(id);
3904 surfCoordinates[0] = xcenter;
3905 surfCoordinates[1] = ycenter;
3906
3907 // Store segment area (weighted with surface averaging factor)
3908 m_surfaceData.surfaceArea(i) = weight * delta_segment;
3909
3910 // Calculate surface normal vector. Simply the gradient and normed
3911 surfaceNormal[0] = 2 * xcenter / (sqrt(4 * xcenter * xcenter + 4 * ycenter * ycenter));
3912 surfaceNormal[1] = 2 * ycenter / (sqrt(4 * xcenter * xcenter + 4 * ycenter * ycenter));
3913
3914 // Store segment normal vector
3915 MFloat* surfNormal = &m_surfaceData.surfaceNormal(id);
3916 surfNormal[0] = surfaceNormal[0];
3917 surfNormal[1] = surfaceNormal[1];
3918 }
3919}
std::vector< MInt > m_noSurfaceElements
Number of (local) surface elements for each surface.
Definition: acasolver.h:310
std::vector< MFloat > m_surfaceWeightingFactor
Weighting factor for each surface (for surface averaging)
Definition: acasolver.h:329
std::vector< MInt > m_surfaceIds
Ids of the surface input file.
Definition: acasolver.h:303
MInt localSurfaceOffset(const MInt sId)
Return local offset of a surface in m_surfaceData.
Definition: acasolver.h:141
constexpr MInt size() const
Return size (i.e., currently used number of nodes)
Definition: container.h:89
void append(const MInt count)
Append nodes to end of tree.
Definition: container.h:223

◆ generateSurfaceData()

template<MInt nDim>
void AcaSolver< nDim >::generateSurfaceData
private

Generate surface data for an analytical test case.

Definition at line 3924 of file acasolver.cpp.

3924 {
3925 TRACE();
3926
3927 const MInt noVars = m_surfaceData.noVars();
3928 TERMM_IF_NOT_COND(noVars == m_noVariables, "number of variables mismatch");
3929
3930 // TODO labels:ACA Read in analytic or semi-analytic
3931 const MBool analytic = true;
3932 /* analytic = Context::getSolverProperty<MBool>("analyticSourceGeneration", m_solverId, AT_,
3933 * &analytic); */
3934
3935 // Initialize every variable with zeros
3936 std::fill_n(&m_surfaceData.variables(0, 0, 0), totalNoSurfaceElements() * noSamples() * noVars, 0.0);
3937
3938 TERMM_IF_NOT_COND(m_dt > 0.0, "Invalid constant time step size: " + std::to_string(m_dt));
3939 // Initialize times (constant timestep size)
3940
3941 for(MInt t = 0; t < noSamples(); t++) {
3942 m_times[t] = m_dt * t;
3943 }
3944
3945 // TODO labels:ACA,toenhance add possibility for superposition of multiple sources with different source parameters
3946 const MInt noSources = 1;
3947
3948 for(MInt sourceId = 0; sourceId < noSources; sourceId++) {
3949 // TODO labels:ACA,toenhance change structure (performance)?
3950 // Iterate over all surface segments and all observers.
3951 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
3952 const MFloat* coord = &m_surfaceData.surfaceCoordinates(segmentId);
3953
3954 SourceVars sourceVars;
3956 sourceVars.p = &m_surfaceData.variables(segmentId, FWH::P);
3957 sourceVars.u = &m_surfaceData.variables(segmentId, FWH::U);
3958 sourceVars.v = &m_surfaceData.variables(segmentId, FWH::V);
3959 sourceVars.w = &m_surfaceData.variables(segmentId, FWH::W);
3960 sourceVars.rho = &m_surfaceData.variables(segmentId, FWH::RHO);
3961 } else {
3962 sourceVars.p = &m_surfaceData.variables(segmentId, FWH_APE::PP);
3963 sourceVars.u = &m_surfaceData.variables(segmentId, FWH_APE::UP);
3964 sourceVars.v = &m_surfaceData.variables(segmentId, FWH_APE::VP);
3965 sourceVars.w = &m_surfaceData.variables(segmentId, FWH_APE::WP);
3966 }
3967
3968 if(analytic) {
3969 // Full analytic formulation
3970 if constexpr(nDim == 2) {
3971 switch(m_sourceType) {
3972 case 0: {
3973 genMonopoleAnalytic2D(coord, m_sourceParameters, sourceVars);
3974 break;
3975 }
3976 case 1: {
3977 genDipoleAnalytic2D(coord, m_sourceParameters, sourceVars);
3978 break;
3979 }
3980 case 2: {
3981 genQuadrupoleAnalytic2D(coord, m_sourceParameters, sourceVars);
3982 break;
3983 }
3984 case 3: {
3986 break;
3987 }
3988 default: {
3989 TERMM(1, "source type not implemented");
3990 break;
3991 }
3992 }
3993 } else {
3994 switch(m_sourceType) {
3995 case 0: {
3996 genMonopoleAnalytic3D(coord, m_sourceParameters, sourceVars);
3997 break;
3998 }
3999 case 1: {
4000 genDipoleAnalytic3D(coord, m_sourceParameters, sourceVars);
4001 break;
4002 }
4003 case 2: {
4004 genQuadrupoleAnalytic3D(coord, m_sourceParameters, sourceVars);
4005 break;
4006 }
4007
4008 default: {
4009 TERMM(1, "source type not implemented");
4010 break;
4011 }
4012 }
4013 }
4014 } else {
4015 TERMM(1, "Error: semi-analytic source generation not implemented.");
4016 // TODO labels:ACA Semi-analytic formulation (numeric differentiation of acoustic potential)
4017 // 1. generate the acoustic potential (without derivatives) for the current
4018 // segment and a surrounding stencil of points
4019 // 2. use finite differences to:
4020 // 2.1 compute the derivatives to get the correct acoustic potential (eg. dipole/quadrupole)
4021 // 2.2 compute the derivatives to get the variables p', u', ...
4022 /* if constexpr(nDim == 2) { */
4023 /* genSurfaceDataNumeric2D(segmentId, m_sourceParameters); */
4024 /* } else { */
4025 /* genSurfaceDataNumeric3D(segmentId, m_sourceParameters); */
4026 /* } */
4027 }
4028 } // end of segmentId for loop
4029 } // end of sourceType loop
4030}
MInt m_noVariables
Definition: acasolver.h:351

◆ generateSurfacePlane()

template<MInt nDim>
void AcaSolver< nDim >::generateSurfacePlane ( const MInt  sId)
private

Definition at line 3593 of file acasolver.cpp.

◆ generateSurfaces()

template<MInt nDim>
void AcaSolver< nDim >::generateSurfaces
private

Generation of surfaces (for analytical cases).

Definition at line 3498 of file acasolver.cpp.

◆ genMonopoleAnalytic2D()

template<MInt nDim>
void AcaSolver< nDim >::genMonopoleAnalytic2D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

2D analytical monopole generation

Definition at line 4035 of file acasolver.cpp.

4035 {
4036 MFloat x = coord[0];
4037 MFloat y = coord[1];
4039
4040 const MFloat omega = param.omega;
4041 const MFloat c0 = 1.0; // by definition
4042 const MFloat rho0 = param.rho0;
4043 const MFloat p0 = rho0 * c0 * c0 / m_gamma;
4044 const MFloat beta = param.beta;
4045 const MFloat amplitude = param.amplitude;
4046 const MFloat u0 = param.Ma * c0;
4047 const MFloat mach = param.Ma;
4048
4049 // Precompute time constant values/factors
4050 const MFloat k = omega / c0;
4051
4052 const MFloat d = sqrt(x * x + beta * beta * y * y);
4053 const MFloat xfd = x / d;
4054 const MFloat yfd = y / d;
4055 const MFloat beta2 = (beta * beta);
4056 const MFloat fbeta2 = 1 / beta2;
4057 const MFloat kfbeta2 = k / (beta * beta);
4058 const MFloat amplwf4beta = amplitude * omega / (4.0 * beta);
4059 const MFloat amplkf4beta3 = amplitude * k / (4.0 * beta * beta2);
4060 const MFloat argHankel = kfbeta2 * d;
4061 const MFloat J0 = j0(argHankel);
4062 const MFloat J1 = j1(argHankel);
4063 const MFloat Y0 = y0(argHankel);
4064 const MFloat Y1 = y1(argHankel);
4065
4066 for(MInt sample = 0; sample < noSamples(); sample++) {
4067 // Note: adapted from acoupot3d/acou_pot.cpp::calc_p/ux/uy/uz_analytic()
4068 const MFloat time = sample * m_dt;
4069 const MFloat arg = omega * time + mach * k * x * fbeta2;
4070
4071 const MFloat cosarg = cos(arg);
4072 const MFloat sinarg = sin(arg);
4073
4074 const MFloat dPhidt = -1.0 * amplwf4beta * (cosarg * J0 + sinarg * Y0);
4075 const MFloat dPhidx =
4076 -1.0 * mach * amplkf4beta3 * (cosarg * J0 + sinarg * Y0) + amplkf4beta3 * xfd * (sinarg * J1 - cosarg * Y1);
4077 const MFloat dPhidy = amplkf4beta3 * yfd * beta2 * (-1.0 * cosarg * Y1 + sinarg * J1);
4078 const MFloat pp = -1.0 * rho0 * (dPhidt + u0 * dPhidx);
4079
4080 if(param.perturbed) {
4081 vars.u[sample] = dPhidx;
4082 vars.v[sample] = dPhidy;
4083 vars.p[sample] = pp;
4084 } else {
4085 vars.u[sample] = dPhidx + u0;
4086 vars.v[sample] = dPhidy;
4087 vars.p[sample] = pp + p0;
4088 vars.rho[sample] = rho0 + pp / (c0 * c0);
4089 }
4090 transformBackToOriginalCoordinate2D(&vars.u[sample], &vars.v[sample]);
4091 }
4092}

◆ genMonopoleAnalytic3D()

template<MInt nDim>
void AcaSolver< nDim >::genMonopoleAnalytic3D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

Definition at line 4097 of file acasolver.cpp.

4097 {
4098 MFloat x = coord[0];
4099 MFloat y = coord[1];
4100 MFloat z = coord[2];
4102
4103 const MFloat omega = param.omega;
4104 const MFloat c0 = 1.0; // by definition
4105 const MFloat rho0 = param.rho0;
4106 const MFloat p0 = rho0 * c0 * c0 / m_gamma;
4107 const MFloat beta = param.beta;
4108 const MFloat amplitude = param.amplitude;
4109 const MFloat u0 = param.Ma * c0;
4110 const MFloat mach = param.Ma;
4111
4112 // Precompute time constant values/factors
4113 // Wavenumber k needs to be dimensionless
4114 MFloat k = omega / c0;
4115
4116 const MFloat d = sqrt(x * x + beta * beta * (y * y + z * z));
4117 const MFloat xfd = x / d;
4118 const MFloat xfd2 = x / (d * d);
4119 const MFloat yfd = y / d;
4120 const MFloat yfd2 = y / (d * d);
4121 const MFloat zfd = z / d;
4122 const MFloat zfd2 = z / (d * d);
4123 const MFloat ampf4pid = amplitude / (4.0 * PI * d);
4124 const MFloat beta2 = (beta * beta);
4125 const MFloat fbeta2 = 1.0 / (beta * beta);
4126
4127 for(MInt sample = 0; sample < noSamples(); sample++) {
4128 // Note: adapted from acoupot3d/acou_pot.cpp::calc_p/ux/uy/uz_analytic()
4129 const MFloat time = sample * m_dt;
4130 const MFloat arg = omega * time - k * (d - mach * x) * fbeta2;
4131
4132 const MFloat cosarg = cos(arg);
4133 const MFloat sinarg = sin(arg);
4134
4135 const MFloat dPhidt = -1.0 * ampf4pid * omega * sinarg;
4136 const MFloat dPhidx = -1.0 * ampf4pid * xfd2 * cosarg + ampf4pid * k * fbeta2 * sinarg * (xfd - mach);
4137 const MFloat dPhidy = -1.0 * ampf4pid * beta2 * yfd2 * cosarg + ampf4pid * k * yfd * sinarg;
4138 const MFloat dPhidz = -1.0 * ampf4pid * beta2 * zfd2 * cosarg + ampf4pid * k * zfd * sinarg;
4139 const MFloat pp = -1.0 * rho0 * (dPhidt + u0 * dPhidx);
4140
4141 if(param.perturbed) {
4142 vars.u[sample] = dPhidx;
4143 vars.v[sample] = dPhidy;
4144 vars.w[sample] = dPhidz;
4145 vars.p[sample] = pp;
4146 } else {
4147 vars.u[sample] = dPhidx + u0;
4148 vars.v[sample] = dPhidy;
4149 vars.w[sample] = dPhidz;
4150 vars.p[sample] = pp + p0;
4151 vars.rho[sample] = rho0 + pp / (c0 * c0);
4152 }
4153 transformBackToOriginalCoordinate3D(&vars.u[sample], &vars.v[sample], &vars.w[sample]);
4154 }
4155}

◆ genQuadrupoleAnalytic2D()

template<MInt nDim>
void AcaSolver< nDim >::genQuadrupoleAnalytic2D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

2D quadrupole analytic

Definition at line 4307 of file acasolver.cpp.

4307 {
4308 MFloat x = coord[0];
4309 MFloat y = coord[1];
4311
4312 const MFloat omega = param.omega;
4313 const MFloat c0 = 1.0; // by definition
4314 const MFloat rho0 = param.rho0;
4315 const MFloat p0 = rho0 * c0 * c0 / m_gamma;
4316 const MFloat beta = param.beta;
4317 const MFloat amplitude = param.amplitude;
4318 const MFloat u0 = param.Ma * c0;
4319 const MFloat mach = param.Ma;
4320
4321 MFloat k = omega / c0;
4322
4323 const MFloat beta2 = beta * beta;
4324 const MFloat fbeta2 = 1 / beta2;
4325 const MFloat d = sqrt(x * x + beta2 * y * y);
4326 const MFloat dargdx = mach * k * fbeta2;
4327 const MFloat argHankel = k * d * fbeta2;
4328 const MFloat K1 = -1.0 * mach * amplitude * k / (4.0 * beta2 * beta);
4329 const MFloat K2 = amplitude / (4.0 * beta);
4330
4331 const MFloat dHdx = k * x * fbeta2 / d;
4332 const MFloat dHdy = k * y / d;
4333
4334 const MFloat dHdxdx = k * y * y / (d * d * d);
4335 const MFloat dHdxdy = -1.0 * k * x * y / (d * d * d);
4336 const MFloat dHdydx = dHdxdy;
4337 const MFloat dHdydy = k * x * x / (d * d * d);
4338
4339 const MFloat dHdxdydx = k * y * (2 * x * x - beta2 * y * y) / (d * d * d * d * d);
4340 const MFloat dHdxdydy = k * x * (2 * beta2 * y * y - x * x) / (d * d * d * d * d);
4341
4342 const MFloat dHdxfH = x / (d * d);
4343 const MFloat dHdxfHdx = -1.0 * (x * x - beta2 * y * y) / (d * d * d * d);
4344 const MFloat dHdxfHdy = -1.0 * 2 * beta2 * x * y / (d * d * d * d);
4345
4346
4347 const MFloat J0 = j0(argHankel);
4348 const MFloat J1 = j1(argHankel);
4349 const MFloat dJ1 = J0 - (1 / argHankel) * J1;
4350
4351 const MFloat Y0 = y0(argHankel);
4352 const MFloat Y1 = y1(argHankel);
4353 const MFloat dY1 = Y0 - (1 / argHankel) * Y1;
4354
4355 for(MInt sample = 0; sample < noSamples(); sample++) {
4356 const MFloat time = sample * m_dt;
4357 const MFloat arg = omega * time + mach * k * x * fbeta2;
4358
4359 const MFloat cosarg = cos(arg);
4360 const MFloat sinarg = sin(arg);
4361
4362 const MFloat dPhidt = K1 * dHdy * sinarg * omega * J1 - K1 * dHdy * cosarg * omega * Y1
4363 + K2 * dHdxdy * cosarg * omega * J1 + K2 * dHdxdy * sinarg * omega * Y1
4364 + K2 * dHdx * dHdy * cosarg * omega * J0 - K2 * dHdxfH * dHdy * cosarg * omega * J1
4365 + K2 * dHdx * dHdy * sinarg * omega * Y0 - K2 * dHdxfH * dHdy * sinarg * omega * Y1;
4366
4367 const MFloat dPhidx =
4368 -1.0 * K1 * dHdydx * cosarg * J1 + K1 * dHdy * sinarg * dargdx * J1 - K1 * dHdy * cosarg * dJ1 * dHdx
4369 - K1 * dHdydx * sinarg * Y1 - K1 * dHdy * cosarg * dargdx * Y1 - K1 * dHdy * sinarg * dY1 * dHdx
4370 + K2 * dHdxdydx * sinarg * J1 + K2 * dHdxdy * cosarg * dargdx * J1 + K2 * dHdxdy * sinarg * dJ1 * dHdx
4371 - K2 * dHdxdydx * cosarg * Y1 + K2 * dHdxdy * sinarg * dargdx * Y1 - K2 * dHdxdy * cosarg * dY1 * dHdx
4372 + K2 * dHdxdx * dHdy * sinarg * J0 + K2 * dHdx * dHdydx * sinarg * J0 + K2 * dHdx * dHdy * cosarg * dargdx * J0
4373 - K2 * dHdx * dHdy * sinarg * J1 * dHdx - K2 * dHdxfHdx * dHdy * sinarg * J1
4374 - K2 * dHdxfH * dHdydx * sinarg * J1 - K2 * dHdxfH * dHdy * cosarg * dargdx * J1
4375 - K2 * dHdxfH * dHdy * sinarg * dJ1 * dHdx - K2 * dHdxdx * dHdy * cosarg * Y0 - K2 * dHdx * dHdydx * cosarg * Y0
4376 + K2 * dHdx * dHdy * sinarg * dargdx * Y0 + K2 * dHdx * dHdy * cosarg * Y1 * dHdx
4377 + K2 * dHdxfHdx * dHdy * cosarg * Y1 + K2 * dHdxfH * dHdydx * cosarg * Y1
4378 - K2 * dHdxfH * dHdy * sinarg * dargdx * Y1 + K2 * dHdxfH * dHdy * cosarg * dY1 * dHdx;
4379
4380 const MFloat dPhidy =
4381 -1.0 * K1 * dHdydy * cosarg * J1 - K1 * dHdy * cosarg * dJ1 * dHdy - K1 * dHdydy * sinarg * Y1
4382 - K1 * dHdy * sinarg * dY1 * dHdy + K2 * dHdxdydy * sinarg * J1 + K2 * dHdxdy * sinarg * dJ1 * dHdy
4383 - K2 * dHdxdydy * cosarg * Y1 - K2 * dHdxdy * cosarg * dY1 * dHdy + K2 * dHdxdy * dHdy * sinarg * J0
4384 + K2 * dHdx * dHdydy * sinarg * J0 - K2 * dHdx * dHdy * sinarg * J1 * dHdy - K2 * dHdxfHdy * dHdy * sinarg * J1
4385 - K2 * dHdxfH * dHdydy * sinarg * J1 - K2 * dHdxfH * dHdy * sinarg * dJ1 * dHdy
4386 - K2 * dHdxdy * dHdy * cosarg * Y0 - K2 * dHdx * dHdydy * cosarg * Y0 + K2 * dHdx * dHdy * cosarg * Y1 * dHdy
4387 + K2 * dHdxfHdy * dHdy * cosarg * Y1 + K2 * dHdxfH * dHdydy * cosarg * Y1
4388 + K2 * dHdxfH * dHdy * cosarg * dY1 * dHdy;
4389
4390 const MFloat pp = -1.0 * rho0 * (dPhidt + u0 * dPhidx);
4391
4392 if(param.perturbed) {
4393 vars.u[sample] = dPhidx;
4394 vars.v[sample] = dPhidy;
4395 vars.p[sample] = pp;
4396 } else {
4397 vars.u[sample] = dPhidx + u0;
4398 vars.v[sample] = dPhidy;
4399 vars.p[sample] = pp + p0;
4400 vars.rho[sample] = rho0 + pp / (c0 * c0);
4401 }
4402 transformBackToOriginalCoordinate2D(&vars.u[sample], &vars.v[sample]);
4403 }
4404}

◆ genQuadrupoleAnalytic3D()

template<MInt nDim>
void AcaSolver< nDim >::genQuadrupoleAnalytic3D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

Definition at line 4409 of file acasolver.cpp.

4409 {
4410 MFloat x = coord[0];
4411 MFloat y = coord[1];
4412 MFloat z = coord[2];
4414
4415 const MFloat omega = param.omega;
4416 const MFloat c0 = 1.0; // by definition
4417 const MFloat rho0 = param.rho0;
4418 const MFloat p0 = rho0 * c0 * c0 / m_gamma;
4419 const MFloat beta = param.beta;
4420 const MFloat amplitude = param.amplitude;
4421 const MFloat u0 = param.Ma * c0;
4422 const MFloat mach = param.Ma;
4423
4424 MFloat k = omega / c0;
4425
4426 const MFloat beta2 = beta * beta;
4427 const MFloat fbeta2 = 1 / beta2;
4428 const MFloat d = sqrt(x * x + beta * beta * (y * y + z * z));
4429 const MFloat d2 = d * d;
4430 const MFloat d3 = d2 * d;
4431 const MFloat fd2 = 1 / d2;
4432 const MFloat fd3 = 1 / d3;
4433 const MFloat C1 = amplitude / (4 * PI);
4434 const MFloat C2 = k * fbeta2;
4435
4436 const MFloat dargdx = -1.0 * C2 * (x / d - mach);
4437 const MFloat dargdy = -1.0 * k * y / d;
4438 const MFloat dargdz = -1.0 * k * z / d;
4439
4440 for(MInt sample = 0; sample < noSamples(); sample++) {
4441 // Note: adapted from acoupot3d/acou_pot.cpp::calc_p/ux/uy/uz_analytic()
4442 const MFloat time = sample * m_dt;
4443 const MFloat arg = omega * time - k * (d - mach * x) * fbeta2;
4444
4445 const MFloat cosarg = cos(arg);
4446 const MFloat sinarg = sin(arg);
4447
4448 const MFloat dPhidt = -1.0 * C1 * 3 * x * y * beta2 * fd2 * fd3 * sinarg * omega
4449 - C1 * 3 * k * x * y * fd2 * fd2 * cosarg * omega + C1 * k * C2 * x * y * fd3 * sinarg * omega
4450 + C1 * mach * k * y * fd3 * cosarg * omega - C1 * mach * k * C2 * y * fd2 * sinarg * omega;
4451
4452 const MFloat dPhidx =
4453 C1 * 3 * y * beta2 * (fd2 * fd3 - 5 * x * x * fd2 * fd2 * fd3) * cosarg
4454 - C1 * 3 * x * y * beta2 * fd2 * fd3 * sinarg * dargdx
4455 - C1 * 3 * k * y * (fd2 * fd2 - 4 * x * x * fd3 * fd3) * sinarg
4456 - C1 * 3 * k * x * y * fd2 * fd2 * cosarg * dargdx - C1 * k * C2 * y * (fd3 - 3 * x * x * fd3 * fd2) * cosarg
4457 + C1 * k * C2 * x * y * fd3 * sinarg * dargdx - C1 * mach * k * y * 3 * x * fd3 * fd2 * sinarg
4458 + C1 * mach * k * y * fd3 * cosarg * dargdx - C1 * mach * k * C2 * y * 2 * x * fd2 * fd2 * cosarg
4459 - C1 * mach * k * C2 * y * fd2 * sinarg * dargdx;
4460
4461 const MFloat dPhidy =
4462 C1 * 3 * x * beta2 * (fd2 * fd3 - 5 * beta2 * y * y * fd2 * fd2 * fd3) * cosarg
4463 - C1 * 3 * x * y * beta * beta * fd3 * fd2 * sinarg * dargdy
4464 - C1 * 3 * k * x * (fd2 * fd2 - 4 * beta2 * y * y * fd3 * fd3) * sinarg
4465 - C1 * 3 * k * x * y * fd2 * fd2 * cosarg * dargdy
4466 - C1 * k * C2 * x * (fd3 - 3 * beta2 * y * y * fd2 * fd3) * cosarg + C1 * k * C2 * x * y * fd3 * sinarg * dargdy
4467 + C1 * mach * k * (fd3 - 3 * beta2 * y * y * fd2 * fd3) * sinarg + C1 * mach * k * y * fd3 * cosarg * dargdy
4468 + C1 * mach * k * C2 * (fd2 - 2 * beta2 * y * y * fd2 * fd2) * cosarg
4469 - C1 * mach * k * C2 * y * fd2 * sinarg * dargdy;
4470
4471 const MFloat dPhidz =
4472 -1.0 * C1 * 15 * x * y * z * beta2 * beta2 * fd2 * fd2 * fd3 * cosarg
4473 - C1 * 3 * x * y * beta2 * fd2 * fd3 * sinarg * dargdz + C1 * 12 * k * x * y * z * beta2 * fd3 * fd3 * sinarg
4474 - C1 * 3 * k * x * y * fd2 * fd2 * cosarg * dargdz + C1 * 3 * k * k * x * y * z * fd2 * fd3 * cosarg
4475 + C1 * k * C2 * x * y * fd3 * sinarg * dargdz - C1 * 3 * mach * k * y * z * beta2 * fd2 * fd3 * sinarg
4476 + C1 * mach * k * y * fd3 * cosarg * dargdz - C1 * 2 * mach * k * k * y * z * fd2 * fd2 * cosarg
4477 - C1 * mach * k * C2 * y * fd2 * sinarg * dargdz;
4478
4479 const MFloat pp = -1.0 * rho0 * (dPhidt + u0 * dPhidx);
4480
4481 if(param.perturbed) {
4482 vars.u[sample] = dPhidx;
4483 vars.v[sample] = dPhidy;
4484 vars.w[sample] = dPhidz;
4485 vars.p[sample] = pp;
4486 } else {
4487 vars.u[sample] = dPhidx + u0;
4488 vars.v[sample] = dPhidy;
4489 vars.w[sample] = dPhidz;
4490 vars.p[sample] = pp + p0;
4491 vars.rho[sample] = rho0 + pp / (c0 * c0);
4492 }
4493 transformBackToOriginalCoordinate3D(&vars.u[sample], &vars.v[sample], &vars.w[sample]);
4494 }
4495}

◆ genVortexConvectionAnalytic2D()

template<MInt nDim>
void AcaSolver< nDim >::genVortexConvectionAnalytic2D ( const MFloat coord,
const SourceParameters param,
SourceVars vars 
)
private

Calculate solution vars for analytical inviscid convecting vortex.

Author
Miro Gondrum
Date
11.05.2023

A vortex is convected in an inviscid flow with M_infty in x-direction. The analytical solution is known to not generate noise. Hence, all noise generate is of erroneous nature.

Definition at line 4506 of file acasolver.cpp.

4507 {
4508 const MFloat x = coord[0];
4509 const MFloat y = coord[1];
4510 constexpr MFloat cs = 1.0; // by definition
4511 const MFloat rho0 = param.rho0;
4512
4513 const MFloat fac = cs / (2.0 * PI);
4514 for(MInt sample = 0; sample < noSamples(); sample++) {
4515 const MFloat t = sample * m_dt;
4516 const MFloat xRel = x - param.Ma * cs * t;
4517 const MFloat yRel = y;
4518 const MFloat r = sqrt(POW2(xRel) + POW2(yRel));
4519 const MFloat theta = atan2(yRel, xRel);
4520 const MFloat utheta = fac * r * exp(0.5 * (1 - r * r));
4521 const MFloat up = utheta * sin(theta);
4522 const MFloat vp = -utheta * cos(theta);
4523 const MFloat pp = pow(1 + (m_gamma - 1) * exp(1 - r * r) / (8.0 * PI * PI), m_gamma / (m_gamma - 1.0)) - 1.0;
4524 if(param.perturbed) {
4525 vars.u[sample] = up;
4526 vars.v[sample] = vp;
4527 vars.p[sample] = pp;
4528 } else {
4529 vars.u[sample] = param.Ma * cs + up;
4530 vars.v[sample] = vp;
4531 vars.p[sample] = pp;
4532 if(vars.rho != nullptr) vars.rho[sample] = rho0 * pow((1.0 + pp), 1.0 / m_gamma);
4533 }
4534 }
4535}
constexpr Real POW2(const Real x)
Definition: functions.h:119

◆ getGlobalObserverCoordinates()

template<MInt nDim>
std::array< MFloat, nDim > AcaSolver< nDim >::getGlobalObserverCoordinates ( const MInt  globalObserverId)
inlineprivate

Definition at line 169 of file acasolver.h.

169 {
170 std::array<MFloat, nDim> coord;
171 for(MInt dir = 0; dir < nDim; dir++) {
172 coord[dir] = a_globalObserverCoordinate(globalObserverId, dir);
173 }
174 return coord;
175 };
MFloat a_globalObserverCoordinate(const MInt globalObserverId, const MInt dir)
Accessor for global observer coordinates.
Definition: acasolver.h:165

◆ getObserverDomainId()

template<MInt nDim>
MInt AcaSolver< nDim >::getObserverDomainId ( const MInt  globalObserverId)
inlineprivate

Definition at line 177 of file acasolver.h.

177 {
178 const MInt minNoObsPerDomain = globalNoObservers() / noDomains();
179 const MInt remainderObs = globalNoObservers() % noDomains();
180 if(globalObserverId < remainderObs * (minNoObsPerDomain + 1)) {
181 return globalObserverId / (minNoObsPerDomain + 1);
182 } else {
183 return (globalObserverId - remainderObs) / minNoObsPerDomain;
184 }
185 };

◆ getSurfaceDataFileName()

template<MInt nDim>
MString AcaSolver< nDim >::getSurfaceDataFileName ( const MInt  surfaceId,
const MInt  fileNo 
)
inlineprivate

Return the name of a surface data \input[in] surfaceId id of the surface element \input[in] fileNo index of the file.

Definition at line 2913 of file acasolver.cpp.

2913 {
2914 TRACE();
2915 const MString baseFileName = "surface_data_";
2916 const MString baseFileNameSuffix = ".Netcdf";
2917 std::ostringstream os;
2918 os << m_inputDir << baseFileName << std::to_string(m_surfaceIds[surfaceId]) << "_" << std::setw(8)
2919 << std::setfill('0') << fileNo << baseFileNameSuffix;
2920 return (MString)os.str();
2921}
MString m_inputDir
I/O.
Definition: acasolver.h:379

◆ globalNoObservers()

template<MInt nDim>
MInt AcaSolver< nDim >::globalNoObservers ( )
inlineprivate

Definition at line 153 of file acasolver.h.

153{ return m_noGlobalObservers; }
MInt m_noGlobalObservers
Number of samples.
Definition: acasolver.h:366

◆ hasSurface()

template<MInt nDim>
MBool AcaSolver< nDim >::hasSurface ( const MInt  surfaceId)
inlineprivate

Definition at line 132 of file acasolver.h.

132{ return m_noSurfaceElements.at(surfaceId) > 0; }

◆ initConversionFactors()

template<MInt nDim>
void AcaSolver< nDim >::initConversionFactors
private

Definition at line 4721 of file acasolver.cpp.

4721 {
4722 // TODO labels:ACA IMHO it does not make sense to have a different dimensions
4723 // or even quantities (wave number or frequency) in the output. The output
4724 // should have the same dimensions for a certain solver to avoid confusion
4725 // when switching between different input solver.
4726 std::stringstream ss;
4727 printMessage("- Init conversion factors");
4728 switch(m_acaResultsNondimMode) {
4729 case NONDIMACA:
4730 case NONDIMSTAGNATION: {
4731 const MFloat constant = 1.0 + (m_gamma - 1.0) * 0.5 * m_MaDim * m_MaDim;
4732 m_input2Aca.length = 1.0;
4733 m_input2Aca.density = pow(constant, (1.0 / (m_gamma - 1.0)));
4734 m_input2Aca.velocity = sqrt(constant);
4736 m_input2Aca.pressure = pow(constant, (m_gamma / (m_gamma - 1.0)));
4737 constexpr MFloat HzToRad = 2.0 * PI;
4739 // .. and corresponding inverse factors
4741 // Default definition is correct -> dump out in ACA dimension
4749 }
4750 break;
4751 }
4752 case NONDIMLB: {
4753 // To reduce some confusion of the LB user. In LB all quantities are made
4754 // non-dimensional with dxLb (cell length at max level), density at
4755 // infinity, and xi_0=dxLb/dtLb. But, the time in the surface sampling
4756 // file is given by t_infty = t * u_infty / L_FV , L_FV=1.
4757 m_input2Aca.density = 1.0;
4758 m_input2Aca.time = 1.0 / m_MaDim; // not LB to ACA, as in sampling file t_infty is dumped
4759 // TODO labels:ACA How to choose dxLb (question of input only)
4760 // const MFloat dxLb = Context::getSolverProperty<MFloat>("dxLb", m_solverId, AT_, 0);
4761 // m_input2Aca.length = dxLb;
4762 m_input2Aca.length = std::numeric_limits<double>::quiet_NaN();
4763 m_input2Aca.velocity = F1BCS;
4765 break;
4766 }
4767 default: {
4768 TERMM(1, "Invalid acaResultsNondimMode: '" + std::to_string(m_acaResultsNondimMode) + "'");
4769 }
4770 }
4771 ss << " MaDim = " << m_MaDim << std::endl;
4772 ss << " Conversion factors input2Aca | aca2Output:" << std::endl;
4773 ss << " velocity = " << m_input2Aca.velocity << " | " << m_aca2Output.velocity << std::endl;
4774 ss << " pressure = " << m_input2Aca.pressure << " | " << m_aca2Output.pressure << std::endl;
4775 ss << " density = " << m_input2Aca.density << " | " << m_aca2Output.density << std::endl;
4776 ss << " time = " << m_input2Aca.time << " | " << m_aca2Output.time << std::endl;
4777 ss << " frequency= " << m_input2Aca.frequency << " | " << m_aca2Output.frequency;
4778 printMessage(ss.str());
4779}
MFloat m_MaDim
Mach number used for change of nondimensionalization.
Definition: acasolver.h:425
MInt m_acaResultsNondimMode
Definition: acasolver.h:288

◆ initObserverPoints()

template<MInt nDim>
void AcaSolver< nDim >::initObserverPoints
private

Initialize the observer points (load/generate coordinates and init collector)

Definition at line 4584 of file acasolver.cpp.

◆ initParallelization()

template<MInt nDim>
void AcaSolver< nDim >::initParallelization
private

Initialize the parallelization, i.e., distribute all surface segments among ranks create communicators etc.

Definition at line 2672 of file acasolver.cpp.

2672 {
2673 TRACE();
2674 printMessage("- Init parallelization");
2675 RECORD_TIMER_START(m_timers[Timers::InitParallelization]);
2676
2680 m_surfaceInputFileName.resize(noSurfaces(), "");
2681
2682 std::vector<MInt> totalNoSegments(noSurfaces());
2683
2684 // TODO labels:ACA maybe do this only on rank 0
2686 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2687 std::vector<MInt> dummyVec{};
2688 // Determine total number of segments for each surface
2689 // const MInt totalNoSegments = readNoSegmentsSurfaceGeneration(sId, dummyVec);
2690 totalNoSegments[sId] = readNoSegmentsSurfaceGeneration(sId, dummyVec);
2691 }
2692 } else {
2693 m_totalNoSamples = -1;
2694
2695 // Determine total number of samples and number of segments for each surface from input data files
2696 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2697 MInt noSamples = -1;
2698 readNoSegmentsAndSamples(sId, totalNoSegments[sId], noSamples, m_surfaceInputFileName[sId]);
2699
2700 // Check that number of samples matches for all surfaces
2701 TERMM_IF_NOT_COND(m_totalNoSamples < 0 || m_totalNoSamples == noSamples,
2702 "number of samples mismatch for different surfaces");
2704 }
2705
2707
2708 // Check noSamples/stride/offset
2709 const MInt usedSampleRange = m_noSamples * m_sampleStride + m_sampleOffset;
2710 TERMM_IF_COND(m_noSamples < 1 || m_sampleStride < 1 || m_sampleOffset < 0 || usedSampleRange > m_totalNoSamples,
2711 "Error: number of samples and stride need to be > 0, offset >= 0 and samples*stride+offset cannot "
2712 "exceed the total number of samples (noSamples="
2713 + std::to_string(m_noSamples) + ", stride=" + std::to_string(m_sampleStride) + ", offset="
2714 + std::to_string(m_sampleOffset) + ", samples*stride+offset=" + std::to_string(usedSampleRange)
2715 + ", totalNoSamples=" + std::to_string(m_totalNoSamples) + ").");
2716
2717 // Only even number of samples
2718 if(m_noSamples % 2 > 0) {
2720 if(domainId() == 0) {
2721 std::cout << "Note: Number of Samples was uneven which is not feasible. The new number of samples is: "
2722 << m_noSamples << std::endl;
2723 }
2724 }
2725 }
2726
2727 // Store global number of segments for all surfaces
2728 std::copy(totalNoSegments.begin(), totalNoSegments.end(), &m_noSurfaceElementsGlobal[0]);
2729
2730 // Determine distribution of surface segments among all processes
2731 const MInt globalNoSegments = std::accumulate(totalNoSegments.begin(), totalNoSegments.end(), 0);
2732
2733 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2734 m_log << "Surface #" << m_surfaceIds[sId] << " has " << totalNoSegments[sId]
2735 << " segments; surface input file name: " << m_surfaceInputFileName[sId]
2736 << "; weighting factor: " << m_surfaceWeightingFactor[sId] << std::endl;
2737 }
2738 m_log << "Global number of segments: " << globalNoSegments << std::endl;
2739 m_log << "Number of samples: " << m_noSamples << " (totalNoSamples = " << m_totalNoSamples
2740 << ", stride = " << m_sampleStride << ", offset = " << m_sampleOffset << ")" << std::endl;
2741
2742 MInt localNoSegments = -1;
2743
2744 // Distribute all segments equally among all domains. This means that a process can have segments
2745 // of different surfaces, e.g., when using only a small number of processes. However, for larger
2746 // production cases it makes sense to limit each process to have only segments of a single surface
2747 // if the I/O of data of different surfaces should be fully parallel.
2749 // Average number of segments (rounded down)
2750 const MInt avgNoSegments = floor(static_cast<MFloat>(globalNoSegments) / static_cast<MFloat>(noDomains()));
2751 localNoSegments = avgNoSegments;
2752 // Equally distribute missing segments
2753 if(domainId() < globalNoSegments - noDomains() * avgNoSegments) {
2754 localNoSegments += 1;
2755 }
2756 } else { // Restrict each rank to have only segments of one surface to improve performance in production cases
2757 std::vector<MInt> noDomainsPerSurface(noSurfaces());
2758 // Average number of segments
2759 const MFloat avgNoSegments = static_cast<MFloat>(globalNoSegments) / static_cast<MFloat>(noDomains());
2760 // Distribute ranks on surfaces
2761 for(MInt i = 0; i < noSurfaces(); i++) {
2762 noDomainsPerSurface[i] = std::max(1, static_cast<MInt>(std::floor(totalNoSegments[i] / avgNoSegments)));
2763 }
2764 // Assign remaining ranks to the surfaces with the highest number of segments per rank
2765 while(noDomains() - std::accumulate(noDomainsPerSurface.begin(), noDomainsPerSurface.end(), 0) > 0) {
2766 MFloat maxWeight = 0.0;
2767 MInt maxIndex = -1;
2768 for(MInt i = 0; i < noSurfaces(); i++) {
2769 const MFloat weight = totalNoSegments[i] / noDomainsPerSurface[i];
2770 if(weight > maxWeight) {
2771 maxWeight = weight;
2772 maxIndex = i;
2773 }
2774 }
2775 noDomainsPerSurface[maxIndex]++;
2776 }
2777 const MInt noDomainsSum = std::accumulate(noDomainsPerSurface.begin(), noDomainsPerSurface.end(), 0);
2778 TERMM_IF_NOT_COND(noDomainsSum == noDomains(),
2779 "number of domains mismatch " + std::to_string(noDomainsSum) + " " + std::to_string(noDomains()));
2780
2781 // Determine the local surface
2782 MInt localSurfaceId = -1;
2783 MInt localSurfaceDomainId = -1;
2784 for(MInt i = 0, sumDomains = 0; i < noSurfaces(); i++) {
2785 if(sumDomains + noDomainsPerSurface[i] > domainId()) {
2786 localSurfaceId = i;
2787 localSurfaceDomainId = domainId() - sumDomains;
2788 break;
2789 }
2790 sumDomains += noDomainsPerSurface[i];
2791 }
2792
2793 const MInt avgNoSegmentsSurface = floor(totalNoSegments[localSurfaceId] / noDomainsPerSurface[localSurfaceId]);
2794 // Determine local number of segments of this surface
2795 localNoSegments = avgNoSegmentsSurface;
2796 if(localSurfaceDomainId
2797 < totalNoSegments[localSurfaceId] - noDomainsPerSurface[localSurfaceId] * avgNoSegmentsSurface) {
2798 localNoSegments += 1;
2799 }
2800 }
2801
2802 // Communicate number of segments per domain
2803 std::vector<MInt> noSegmentsPerDomain(noDomains());
2804 MPI_Allgather(&localNoSegments, 1, type_traits<MInt>::mpiType(), &noSegmentsPerDomain[0], 1,
2805 type_traits<MInt>::mpiType(), mpiComm(), AT_, "localNoSegments", "noSegmentsPerDomain[0]");
2806
2807 // Sanity check
2808 const MInt globalCount = std::accumulate(noSegmentsPerDomain.begin(), noSegmentsPerDomain.end(), 0);
2809 TERMM_IF_NOT_COND(globalCount == globalNoSegments, "globalNoSegments mismatch");
2810
2811 // Compute domain offsets
2812 std::vector<MInt> domainSegmentOffsets(std::max(noDomains() + 1, 1));
2813 domainSegmentOffsets[0] = 0;
2814 for(MInt i = 1; i < noDomains() + 1; i++) {
2815 domainSegmentOffsets[i] = domainSegmentOffsets[i - 1] + noSegmentsPerDomain[i - 1];
2816 }
2817
2818 MIntScratchSpace noSegments_(noDomains(), noSurfaces(), AT_, "noSegments_");
2819
2820 MInt surfaceOffset = 0;
2821 // Check which surfaces are present on the local rank
2822 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2823 const MInt nextSurfaceOffset = surfaceOffset + totalNoSegments[sId];
2824 const MInt start = domainSegmentOffsets[domainId()];
2825 const MInt end = domainSegmentOffsets[domainId()] + localNoSegments;
2826
2827 MInt noLocalSegments = 0;
2828 MInt localSegmentsOffset = 0;
2829
2830 if(start < surfaceOffset && end >= surfaceOffset) {
2831 // First local segment belongs to a previous surface but last local segment belongs to current
2832 // or a subsequent surface
2833 noLocalSegments = std::min(totalNoSegments[sId], end - surfaceOffset);
2834 localSegmentsOffset = 0;
2835 } else if(start >= surfaceOffset && start < nextSurfaceOffset) {
2836 // First local segment belongs to this surface
2837 noLocalSegments = std::min(nextSurfaceOffset - start, end - start);
2838 localSegmentsOffset = start - surfaceOffset;
2839 }
2840
2841 m_noSurfaceElements[sId] = noLocalSegments;
2842 m_surfaceElementOffsets[sId] = localSegmentsOffset;
2843
2844 // Store in communication buffer
2845 noSegments_(domainId(), sId) = noLocalSegments;
2846
2847 // Set new offset for next surface
2848 surfaceOffset = nextSurfaceOffset;
2849 }
2850
2851 MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &noSegments_[0], noSurfaces(), type_traits<MInt>::mpiType(),
2852 mpiComm(), AT_, "MPI_IN_PLACE", "noSegments_[0]");
2853
2854 m_mpiCommSurface.resize(noSurfaces());
2856 m_domainIdSurface.resize(noSurfaces());
2857
2858 // Create MPI communicators for each surface
2859 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2860 MIntScratchSpace domains(noDomains(), AT_, "domains");
2861 MInt noDomains_ = 0;
2862
2863 // Determine list of subdomains with segments of this surface
2864 for(MInt d = 0; d < noDomains(); d++) {
2865 if(noSegments_(d, sId) > 0) {
2866 domains[noDomains_] = d;
2867 noDomains_++;
2868 }
2869 }
2870
2871 m_log << "Create MPI communicator for surface #" << m_surfaceIds[sId] << " with " << noDomains_
2872 << " ranks:" << std::endl;
2873#ifndef NDEBUG
2874 for(MInt d = 0; d < noDomains_; d++) {
2875 m_log << " * local rank #" << d << " global rank #" << domains[d] << " with " << noSegments_(domains[d], sId)
2876 << " segments" << std::endl;
2877 }
2878#endif
2879
2880 // Obtain new group
2881 MPI_Group globalGroup, localGroup;
2882 MPI_Comm_group(mpiComm(), &globalGroup, AT_, "globalGroup");
2883 MPI_Group_incl(globalGroup, noDomains_, &domains[0], &localGroup, AT_);
2884
2885 // Create new communicator and clean up
2886 MPI_Comm_create(mpiComm(), localGroup, &m_mpiCommSurface[sId], AT_,
2887 "m_mpiCommSurface[" + std::to_string(sId) + "]");
2888
2889 MPI_Group_free(&globalGroup, AT_);
2890 MPI_Group_free(&localGroup, AT_);
2891
2892 if(noSurfaceElements(sId) > 0) {
2893 // If surface is active on current domain, determine local rank and number of domains
2894 MPI_Comm_rank(m_mpiCommSurface[sId], &m_domainIdSurface[sId]);
2895 MPI_Comm_size(m_mpiCommSurface[sId], &m_noDomainsSurface[sId]);
2896
2897 TERMM_IF_NOT_COND(m_noDomainsSurface[sId] == noDomains_, "number of domains mismatch");
2898 } else {
2899 // Reset for inactive surface
2900 m_domainIdSurface[sId] = -1;
2901 m_noDomainsSurface[sId] = -1;
2902 }
2903 }
2904
2905 RECORD_TIMER_STOP(m_timers[Timers::InitParallelization]);
2906}
void readNoSegmentsAndSamples(const MInt surfaceId, MInt &noSegments, MInt &noSamples, MString &inputFileName)
Read the number of segments and samples for the given surface id.
Definition: acasolver.cpp:2994
MInt m_sampleStride
Stride of used samples in input data files.
Definition: acasolver.h:339
MBool m_generateSurfaceData
Enable generation of analytical surface data.
Definition: acasolver.h:392
MBool m_allowMultipleSurfacesPerRank
Allow multiple surfaces per rank.
Definition: acasolver.h:313
MInt m_sampleOffset
Offset in input data files from which to start reading samples.
Definition: acasolver.h:341
std::vector< MString > m_surfaceInputFileName
Surface input file names that were used for sampling.
Definition: acasolver.h:332
MInt noSurfaces()
Return number of surfaces.
Definition: acasolver.h:129
std::vector< MInt > m_surfaceElementOffsets
Local surface element offsets for each surface.
Definition: acasolver.h:319
MInt m_totalNoSamples
Total number of samples in input data files.
Definition: acasolver.h:337
MInt readNoSegmentsSurfaceGeneration(const MInt sId, std::vector< MInt > &noSegments, const MInt lengthCheck=-1)
Determine the number of segments to be generated for a surface, returns the total number of segments ...
Definition: acasolver.cpp:3541
std::vector< MInt > m_noDomainsSurface
Surface local number of domains.
Definition: acasolver.h:324
std::vector< MInt > m_noSurfaceElementsGlobal
Total number of surface elements for each surface.
Definition: acasolver.h:316
MInt m_noSamples
Number of samples.
Definition: acasolver.h:335
MInt noSurfaceElements(const MInt surfaceId)
Return number of (local) surfaces elements for a surface.
Definition: acasolver.h:135
std::vector< MInt > m_domainIdSurface
Surface local domain id.
Definition: acasolver.h:326
std::vector< MPI_Comm > m_mpiCommSurface
Surface local MPI communicators.
Definition: acasolver.h:322
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_create, but updates the number of MPI communicators
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup, const MString &name)
same as MPI_Group_incl
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group, const MString &name, const MString &varname)
same as MPI_Comm_group
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
int MPI_Group_free(MPI_Group *group, const MString &name)
same as MPI_Group_free

◆ initSolver()

template<MInt nDim>
void AcaSolver< nDim >::initSolver
overridevirtual

Implements Solver.

Definition at line 28 of file acasolver.cpp.

28 {
29 TRACE();
30
31 // Initialize all solver-wide timers
32 initTimers();
33 // Input/output
35 // Numerical method
37}
void setNumericalProperties()
Read/set all numerical properties.
Definition: acasolver.cpp:421
void initTimers()
Initialize solver timers.
Definition: acasolver.cpp:41
void setInputOutputProperties()
Read/set all I/O related properties.
Definition: acasolver.cpp:107

◆ initTimers()

template<MInt nDim>
void AcaSolver< nDim >::initTimers
private

Definition at line 41 of file acasolver.cpp.

41 {
42 TRACE();
43
44 // Invalidate timer ids
45 std::fill(m_timers.begin(), m_timers.end(), -1);
46
47 // Create timer group & timer for solver, and start the timer
48 NEW_TIMER_GROUP_NOCREATE(m_timerGroup, "AcaSolver (solverId = " + std::to_string(m_solverId) + ")");
49 NEW_TIMER_NOCREATE(m_timers[Timers::SolverType], "total object lifetime", m_timerGroup);
50 RECORD_TIMER_START(m_timers[Timers::SolverType]);
51
52 // Create regular solver-wide timers
53 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Run], "run", m_timers[Timers::SolverType]);
54
55 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitParallelization], "initParallelization", m_timers[Timers::Run]);
56 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReadSurfaceData], "readSurfaceData", m_timers[Timers::Run]);
57
58 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitObservers], "initObservers", m_timers[Timers::Run]);
59 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSourceTerms], "calcSourceTerms", m_timers[Timers::Run]);
60 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::WindowAndTransformSources], "windowAndTransformSources",
62 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSurfaceIntegrals], "calcSurfaceIntegrals", m_timers[Timers::Run]);
63 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CombineSurfaceIntegrals], "combineSurfaceIntegrals", m_timers[Timers::Run]);
64 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::BacktransformObservers], "backtransformObservers", m_timers[Timers::Run]);
65 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveObserverSignals], "saveObserverSignals", m_timers[Timers::Run]);
66 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Postprocessing], "postprocessing", m_timers[Timers::Run]);
67}
MInt m_timerGroup
Definition: acasolver.h:446

◆ interpolateFromSourceToObserverTime()

template<MInt nDim>
void AcaSolver< nDim >::interpolateFromSourceToObserverTime ( const MFloat  distMinObservers,
MFloat *const  p_perturbedFWH 
)
private

Definition at line 2123 of file acasolver.cpp.

2123 {
2124 const MFloat inverseFourPI = 1.0 / 4.0 / PI;
2125
2126 // Loop over all the observer timeSteps
2127 maia::parallelFor<false>(0, noSamples(), [=](MInt t) {
2128 // Set the observer time
2129 MFloat timeObserver = t * m_dt + distMinObservers;
2130
2131 // initialize surface integral
2132 MFloat sumFwhPP = 0.0;
2133
2134 // Surface element loop
2135 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
2136 // initialize interpolation value
2137 MFloat interpolateFwhPP = 0.0;
2138 MInt t_lower = 0;
2139 MInt t_upper = noSamples() - 1;
2140
2141 // Read the observer lower/upper bound
2142 MFloat timeObserver_lower = m_surfaceData.variables(segmentId, FWH_TIME::timeObs, t_lower);
2143 MFloat timeObserver_upper = m_surfaceData.variables(segmentId, FWH_TIME::timeObs, t_upper);
2144
2145 // Search in FWH_TIME::timeObs
2146 if(timeObserver < timeObserver_lower || timeObserver > timeObserver_upper) {
2147 // In case the timeObserver is out of bound
2148 interpolateFwhPP = 0.0;
2149 } else if(approx(timeObserver, timeObserver_lower, MFloatEps)) {
2150 // In case the timeObserver is at the lower bound
2151 interpolateFwhPP = m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, t_lower);
2152 } else if(approx(timeObserver, timeObserver_upper, MFloatEps)) {
2153 // In case the timeObserver is at the upper bound
2154 interpolateFwhPP = m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, t_upper);
2155 } else {
2156 // In the case of: timeObserver_lower < timeObserver < timeObserver_upper
2157 // Use binary search algorithm to search
2158
2159 MInt t_range = t_upper - t_lower;
2160 do {
2161 // Compute t_mid
2162 const MFloat t_mid = (t_range % 2 == 0) ? ((t_lower + t_upper) / 2) : ((t_lower + t_upper - 1) / 2);
2163 const MFloat timeObserver_mid = m_surfaceData.variables(segmentId, FWH_TIME::timeObs, t_mid);
2164
2165 if(approx(timeObserver, timeObserver_mid, MFloatEps)) {
2166 // In case the timeObserver is at the middle
2167 interpolateFwhPP = m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, t_mid);
2168 break;
2169 }
2170
2171 // Update t_upper and t_lower
2172 if(timeObserver < timeObserver_mid) {
2173 t_upper = t_mid;
2174 } else if(timeObserver > timeObserver_mid) {
2175 t_lower = t_mid;
2176 }
2177 t_range = t_upper - t_lower;
2178
2179 // For the smallest un-dividable region, do linear interpolation to get the observer fwhPP
2180 if(t_range == 1) {
2181 timeObserver_lower = m_surfaceData.variables(segmentId, FWH_TIME::timeObs, t_lower);
2182 timeObserver_upper = m_surfaceData.variables(segmentId, FWH_TIME::timeObs, t_upper);
2183 const MFloat fwhPP_lower = m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, t_lower);
2184 const MFloat fwhPP_upper = m_surfaceData.variables(segmentId, FWH_TIME::fwhPP, t_upper);
2185 const MFloat fwhPP_slop = (fwhPP_upper - fwhPP_lower) / (timeObserver_upper - timeObserver_lower);
2186 interpolateFwhPP = fwhPP_lower + (timeObserver - timeObserver_lower) * fwhPP_slop;
2187 break;
2188 }
2189 } while(t_range > 1);
2190 } // End of the search in FWH_TIME::timeObs
2191
2192 sumFwhPP += interpolateFwhPP;
2193 } // End of the surface loop
2194
2195 p_perturbedFWH[t] = inverseFourPI * sumFwhPP;
2196 }); // End of the observer time loop (parallel)
2197}

◆ isActive()

template<MInt nDim>
MBool AcaSolver< nDim >::isActive ( ) const
inlineoverridevirtual

Return if the solver is active on this rank; needs to be implemented in derived solver since access to gridproxy not possible here

Reimplemented from Solver.

Definition at line 103 of file acasolver.h.

103{ return true; } // All ranks are active

◆ loadObserverSignals()

template<MInt nDim>
void AcaSolver< nDim >::loadObserverSignals
private

Definition at line 2477 of file acasolver.cpp.

2477 {
2478 TRACE();
2479 RECORD_TIMER_START(m_timers[Timers::LoadObserverSignals]);
2480 using namespace maia::parallel_io;
2481
2482 const MInt obsOffset = observerOffset();
2483 const MInt obsCount = noObservers();
2484
2485 std::stringstream ss;
2486 ss << "- Load observer signals from file: " << m_acaPostprocessingFile << std::endl;
2487 printMessage(ss.str());
2488 ParallelIo file(m_acaPostprocessingFile, PIO_READ, mpiComm());
2489
2490 // read times and frequencies on rank 0 and broadcast
2491 if(domainId() == 0) {
2492 file.setOffset(noSamples(), 0);
2493 } else {
2494 file.setOffset(0, 0);
2495 }
2496 file.readArray(&m_times[0], "time");
2497 file.readArray(&m_frequencies[0], "frequency");
2498
2499 MPI_Bcast(&m_times[0], noSamples(), type_traits<MFloat>::mpiType(), 0, mpiComm(), AT_, "&m_times[0]");
2500 MPI_Bcast(&m_frequencies[0], noSamples(), type_traits<MFloat>::mpiType(), 0, mpiComm(), AT_, "&m_frequencies[0]");
2501
2502 // Read observer data in time domain
2503 file.setOffset(obsCount, obsOffset, 2);
2504 ScratchSpace<MFloat> pressure_time(std::max(obsCount, 1), noSamples(), AT_, "pressure_time");
2505
2506 file.readArray(&pressure_time[0], "pressure_time");
2507 for(MInt obs = 0; obs < obsCount; obs++) {
2508 for(MInt t = 0; t < noSamples(); t++) {
2509 m_observerData.variables(obs, 0, t) = pressure_time(obs, t);
2510 }
2511 }
2512
2513 // Read observer data in frequency domain
2514 file.setOffset(obsCount, obsOffset, 2);
2515 ScratchSpace<MFloat> pressure_frequency(std::max(obsCount, 1), 2 * noSamples(), AT_, "pressure_frequency");
2516 file.readArray(&pressure_frequency[0], "pressure_frequency");
2517
2518 for(MInt obs = 0; obs < obsCount; obs++) {
2519 for(MInt f = 0; f < noSamples(); f++) {
2520 m_observerData.complexVariables(obs, 0, f, 0) = pressure_frequency(obs, 2 * f);
2521 m_observerData.complexVariables(obs, 0, f, 1) = pressure_frequency(obs, 2 * f + 1);
2522 }
2523 }
2524
2525 RECORD_TIMER_STOP(m_timers[Timers::LoadObserverSignals]);
2526}
MString m_acaPostprocessingFile
Definition: acasolver.h:442
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast

◆ localSurfaceOffset()

template<MInt nDim>
MInt AcaSolver< nDim >::localSurfaceOffset ( const MInt  sId)
inlineprivate

Definition at line 141 of file acasolver.h.

141 {
142 return std::accumulate(&m_noSurfaceElements.at(0), &m_noSurfaceElements.at(sId), 0);
143 }

◆ noInternalCells()

template<MInt nDim>
MInt AcaSolver< nDim >::noInternalCells ( ) const
inlineoverridevirtual

Implements Solver.

Definition at line 114 of file acasolver.h.

114{ return 0; }

◆ noObservers()

template<MInt nDim>
MInt AcaSolver< nDim >::noObservers ( )
inlineprivate

Definition at line 149 of file acasolver.h.

149{ return m_noObservers; }

◆ noSamples()

template<MInt nDim>
MInt AcaSolver< nDim >::noSamples ( )
inlineprivate

Definition at line 146 of file acasolver.h.

146{ return m_noSamples; }

◆ noSurfaceElements()

template<MInt nDim>
MInt AcaSolver< nDim >::noSurfaceElements ( const MInt  surfaceId)
inlineprivate

Definition at line 135 of file acasolver.h.

135{ return m_noSurfaceElements.at(surfaceId); }

◆ noSurfaces()

template<MInt nDim>
MInt AcaSolver< nDim >::noSurfaces ( )
inlineprivate

Definition at line 129 of file acasolver.h.

129{ return m_noSurfaces; }
MInt m_noSurfaces
Number of surfaces.
Definition: acasolver.h:301

◆ noVariables()

template<MInt nDim>
MInt AcaSolver< nDim >::noVariables ( ) const
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 113 of file acasolver.h.

113{ return 0; }

◆ observerOffset()

template<MInt nDim>
MInt AcaSolver< nDim >::observerOffset ( )
inlineprivate

Definition at line 151 of file acasolver.h.

151{ return m_offsetObserver; }

◆ postprocessObserverSignals()

template<MInt nDim>
void AcaSolver< nDim >::postprocessObserverSignals
private

Definition at line 2531 of file acasolver.cpp.

2531 {
2532 TRACE();
2533 RECORD_TIMER_START(m_timers[Timers::Postprocessing]);
2534 printMessage("- Post process observer signals");
2535
2536 // Loop over all postprocessing operations
2537 for(MInt op = 0; op < m_noPostprocessingOps; op++) {
2538 const MInt operation = m_postprocessingOps[op];
2539 switch(operation) {
2540 case PP::RMS_PRESSURE: {
2541 m_post.push_back(std::make_unique<AcaPostProcessingRMS<nDim>>(mpiComm()));
2542 break;
2543 }
2544 case PP::OASPL: {
2545 m_post.push_back(std::make_unique<AcaPostProcessingOASPL<nDim>>(mpiComm()));
2546 break;
2547 }
2548 case PP::SPL: {
2549 m_post.push_back(std::make_unique<AcaPostProcessingSPL<nDim>>(mpiComm()));
2550 break;
2551 }
2552 case PP::pABS: {
2553 m_post.push_back(std::make_unique<AcaPostProcessingPABS<nDim>>(mpiComm()));
2554 break;
2555 }
2556 case PP::calcObsPress: {
2557 TERMM_IF_NOT_COND(m_generateSurfaceData, "Only useful for analytical testcases with generated surface data.");
2559 break;
2560 }
2561 default: {
2562 std::cerr << " "
2563 << "skippinginvalid postprocessing operation: " << operation << std::endl;
2564 break;
2565 }
2566 }
2567 }
2568
2569 for(auto&& post : m_post) {
2572 for(MInt obs = 0; obs < noObservers(); obs++) {
2573 post->calc(obs, &m_observerData.variables(obs, 0), &m_observerData.complexVariables(obs, 0));
2574 }
2575 post->finish();
2576 }
2577
2578 RECORD_TIMER_STOP(m_timers[Timers::Postprocessing]);
2579}
ACA post processing class for overall sound pressure calculation.
ACA post processing class for absoulte pressure calculation.
ACA post processing class for calculation of root mean square pressure.
ACA post processing class for sound pressure level calculation.
MInt m_noPostprocessingOps
Post Processing of observer signals.
Definition: acasolver.h:438
std::vector< MInt > m_postprocessingOps
Definition: acasolver.h:439
void calcObsPressureAnalytic()
Definition: acasolver.cpp:2583
std::vector< std::unique_ptr< AcaPostProcessing > > m_post
Definition: acasolver.h:272
static constexpr const MInt RMS_PRESSURE
Definition: acasolver.h:530
static constexpr const MInt OASPL
Definition: acasolver.h:531
static constexpr const MInt pABS
Definition: acasolver.h:533
static constexpr const MInt SPL
Definition: acasolver.h:532
static constexpr const MInt calcObsPress
Definition: acasolver.h:534

◆ postTimeStep()

template<MInt nDim>
void AcaSolver< nDim >::postTimeStep ( )
inlinevirtual

Implements Solver.

Definition at line 116 of file acasolver.h.

116{}

◆ preTimeStep()

template<MInt nDim>
void AcaSolver< nDim >::preTimeStep ( )
inlineoverridevirtual

Implements Solver.

Definition at line 115 of file acasolver.h.

115{}

◆ printMessage()

template<MInt nDim>
void AcaSolver< nDim >::printMessage ( const MString  msg)
inlineprivate

Definition at line 203 of file acasolver.h.

203 {
204 m_log << msg << std::endl;
205 if(domainId() == 0) std::cout << msg << std::endl;
206 };

◆ readNoSegmentsAndSamples()

template<MInt nDim>
void AcaSolver< nDim >::readNoSegmentsAndSamples ( const MInt  surfaceId,
MInt noSegments,
MInt noSamples,
MString inputFileName 
)
private

Definition at line 3000 of file acasolver.cpp.

◆ readNoSegmentsSurfaceGeneration()

template<MInt nDim>
MInt AcaSolver< nDim >::readNoSegmentsSurfaceGeneration ( const MInt  sId,
std::vector< MInt > &  noSegments,
const MInt  lengthCheck = -1 
)
private

Definition at line 3543 of file acasolver.cpp.

◆ readSurfaceData()

template<MInt nDim>
void AcaSolver< nDim >::readSurfaceData
private

Definition at line 2925 of file acasolver.cpp.

2925 {
2926 TRACE();
2927 printMessage("- Read surface data");
2928 RECORD_TIMER_START(m_timers[Timers::ReadSurfaceData]);
2929
2930 // Set data sizes in surface data collector
2934
2935 // Reset surface data collector to total number of local surface elements
2936 const MInt totalNoSurfaceElements_ = totalNoSurfaceElements();
2937 TERMM_IF_COND(totalNoSurfaceElements_ < 1, "Less surface elements than computational ranks is critical.");
2938 m_surfaceData.reset(totalNoSurfaceElements_);
2939
2940 // Set storage size for times and frequencies
2941 m_times.resize(noSamples());
2942 m_frequencies.resize(noSamples());
2943
2944 // Read in the surface data and store in m_surfaceData
2945 // or generate the surface elements and the corresponding analytical input data
2949
2950 // Testing: store generated data
2951 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2952 if(hasSurface(sId) && m_storeSurfaceData) {
2953 storeSurfaceData(sId);
2954 }
2955 }
2956 } else if(m_acaPostprocessingMode) {
2957 // Nothing to do if just postprocessing is enabled
2958 } else {
2959 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2960 // Read data if surface present on local rank
2961 if(hasSurface(sId)) {
2963
2964 // Testing: store data for validating the I/O
2965 if(m_storeSurfaceData) {
2966 storeSurfaceData(sId);
2967 }
2968 }
2969 }
2970
2971 { // Compare the loaded times on all ranks
2972 ScratchSpace<MFloat> timesBuffer(noSamples(), AT_, "timesBuffer");
2973 std::copy_n(&m_times[0], noSamples(), &timesBuffer[0]);
2974
2975 MPI_Bcast(&timesBuffer[0], noSamples(), type_traits<MFloat>::mpiType(), 0, mpiComm(), AT_, "&timesBuffer[0]");
2976
2977 for(MInt i = 0; i < noSamples(); i++) {
2978 TERMM_IF_COND(!approx(timesBuffer[i], m_times[i], MFloatEps), "Error: times for surfaces do not match.");
2979 }
2980 }
2981
2982 // The simulation non-dimensionalises with different variables! For the FWH simulation one needs
2983 // to change how the numbers are non-dimensionalized
2985 computeDt();
2986 }
2987
2988 RECORD_TIMER_STOP(m_timers[Timers::ReadSurfaceData]);
2989}
void generateSurfaceData()
Generation of analytical input data.
Definition: acasolver.cpp:3924
MInt m_noComplexVariables
Definition: acasolver.h:352
void storeSurfaceData(const MInt surfaceId)
Store the surface data. Note: used for validating the data input and for the output of generated data...
Definition: acasolver.cpp:3428
void generateSurfaces()
Generation of surfaces.
Definition: acasolver.cpp:3493
void changeDimensionsSurfaceData()
Change of the non-dimensionalization of input data from the stagnation state (0) non-dim....
Definition: acasolver.cpp:4784
void readSurfaceDataFromFile(const MInt surfaceId)
Read the data for one surface.
Definition: acasolver.cpp:3064
MBool m_acaPostprocessingMode
Definition: acasolver.h:441
MBool m_storeSurfaceData
Prefix for all output files.
Definition: acasolver.h:383
MBool hasSurface(const MInt surfaceId)
Return if this rank has data of this surface.
Definition: acasolver.h:132
void computeDt()
Definition: acasolver.cpp:4845
void setNoVars(const MInt noVars_)
Set number of variables.
void reset()
Reset, re-create data structures with given capacity, and set size to zero.
void setNoComplexVars(const MInt noComplexVars_)
Set number of complex variables.
void setNoSamples(const MInt noSamples_)
Set number of samples.

◆ readSurfaceDataFromFile()

template<MInt nDim>
void AcaSolver< nDim >::readSurfaceDataFromFile ( const MInt  surfaceId)
private

Definition at line 3064 of file acasolver.cpp.

3064 {
3065 TRACE();
3066 using namespace maia::parallel_io;
3067
3068 const MInt count = m_noSurfaceElements[surfaceId];
3069 const MInt offset = m_surfaceElementOffsets[surfaceId];
3070 const MInt surfaceOffset = localSurfaceOffset(surfaceId);
3071
3072 const MString measureName = (nDim == 3) ? "area" : "length";
3073
3074 // Create surface elements and store its data in m_surfaceData
3075 auto createSurfaceElements = [&](const MInt l_surfaceId,
3076 const MFloatScratchSpace& l_measure,
3077 const MFloatScratchSpace& l_coordinates,
3078 const MFloatScratchSpace& l_normalVector) {
3079 MFloat totalSurfaceMeasure = 0.0;
3080 MFloat totalSurfaceMeasureWeighted = 0.0;
3081
3082 const MFloat weight = m_surfaceWeightingFactor[l_surfaceId];
3083 for(MInt i = 0; i < count; i++) {
3084 const MInt id = surfaceOffset + i;
3085 // Add a new surface element
3087 // Check that the total size of m_surfaceData is correct
3088 TERMM_IF_NOT_COND(m_surfaceData.size() == id + 1, "m_surfaceData size mismatch.");
3089
3090 MFloat* surfCoordinates = &m_surfaceData.surfaceCoordinates(id);
3091 MFloat* surfNormal = &m_surfaceData.surfaceNormal(id);
3092
3093 // Store segment area/length (weighted with surface averaging factor)
3094 m_surfaceData.surfaceArea(id) = weight * l_measure[i];
3095 totalSurfaceMeasure += l_measure[i];
3096 totalSurfaceMeasureWeighted += (weight * l_measure[i]);
3097
3098 // Set coordinates and normal vector
3099 for(MInt j = 0; j < nDim; j++) {
3100 surfCoordinates[j] = l_coordinates[i * nDim + j];
3101 surfNormal[j] = l_normalVector[i * nDim + j];
3102 }
3103 }
3104
3105 // Compute total area/length of surface
3106 MPI_Allreduce(MPI_IN_PLACE, &totalSurfaceMeasure, 1, type_traits<MFloat>::mpiType(), MPI_SUM,
3107 m_mpiCommSurface[surfaceId], AT_, "MPI_IN_PLACE", "totalSurfaceMeasure");
3108 MPI_Allreduce(MPI_IN_PLACE, &totalSurfaceMeasureWeighted, 1, type_traits<MFloat>::mpiType(), MPI_SUM,
3109 m_mpiCommSurface[surfaceId], AT_, "MPI_IN_PLACE", "totalSurfaceMeasureWeighted");
3110 if(m_domainIdSurface[surfaceId] == 0) {
3111 std::cout << "Total " << measureName << " of surface #" << surfaceId << ": " << totalSurfaceMeasure
3112 << " (weighted: " << totalSurfaceMeasureWeighted << ")" << std::endl;
3113 }
3114 };
3115
3117 const MString fileName = m_inputDir
3118 + Context::getSolverProperty<MString>(
3119 "surfaceDataFileName_" + std::to_string(m_surfaceIds[surfaceId]), m_solverId, AT_);
3120 ParallelIo file(fileName, PIO_READ, m_mpiCommSurface[surfaceId]);
3121
3122 MFloatScratchSpace coordinates(count * nDim, AT_, "coordinates");
3123 MFloatScratchSpace normalVector(count * nDim, AT_, "normalVector");
3124 MFloatScratchSpace measure(count, AT_, "measure");
3125
3126 // Read surface area/length
3127 file.setOffset(count, offset);
3128 file.readArray(&measure[0], measureName);
3129
3130 // Read coordinates and normal vectors
3131 file.setOffset(count, offset, 2);
3132 file.readArray(&coordinates[0], "coordinates");
3133 file.readArray(&normalVector[0], "normalVector");
3134
3135 // Create surface elements and store its data in m_surfaceData
3136 createSurfaceElements(surfaceId, measure, coordinates, normalVector);
3137
3138 // Read times only on surface local rank 0 and broadcast to other ranks in this communicator
3139 ScratchSpace<MFloat> timesBuffer(m_totalNoSamples, AT_, "timesBuffer");
3140 if(m_domainIdSurface[surfaceId] == 0) {
3141 // Read full array, then copy selected range to m_times
3142 file.setOffset(m_totalNoSamples, 0);
3143 file.readArray(&timesBuffer[0], "time");
3144
3145 // Check the times with those of other surfaces already loaded on this rank (before overwriting them), later
3146 // cross-check the times with all surfaces
3147 if(m_hasTimes) {
3148 for(MInt i = 0; i < noSamples(); i++) {
3149 TERMM_IF_COND(!approx(timesBuffer[m_sampleOffset + i * m_sampleStride], m_times[i], MFloatEps),
3150 "Error: local times for surfaces do not match.");
3151 }
3152 }
3153
3154 // Store times in m_times
3155 if(m_sampleStride == 1) {
3156 std::copy_n(&timesBuffer[m_sampleOffset], noSamples(), &m_times[0]);
3157 } else {
3158 for(MInt i = 0; i < noSamples(); i++) {
3159 m_times[i] = timesBuffer[m_sampleOffset + i * m_sampleStride];
3160 }
3161 }
3162 } else {
3163 file.setOffset(0, 0);
3164 file.readArray(&timesBuffer[0], "time");
3165 }
3166
3168 "&m_times[0]");
3169 m_hasTimes = true;
3170
3171 // Set 2D offset (second dimension is the time axis which is set internally to read all samples)
3172 // TODO labels:ACA,IO directly read only selected sample range once this is supported by the ParallelIO class
3173 file.setOffset(count, offset, 2);
3174
3175 // Data buffer
3176 ScratchSpace<MFloat> varData(count, m_totalNoSamples, AT_, "varData");
3177 // Read datasets and store in m_surfaceData
3178 for(auto& var : m_inputVars) {
3179 const MString varName = var.first;
3180
3181 if(m_domainIdSurface[surfaceId] == 0) {
3182 std::cout << "Surface #" << m_surfaceIds[surfaceId] << ": Loading variable: " << varName << std::endl;
3183 }
3184
3185 file.readArray(&varData[0], varName);
3186
3187 const MInt varIndex = var.second;
3188 for(MInt i = 0; i < count; i++) {
3189 const MInt id = surfaceOffset + i;
3190 for(MInt t = 0; t < noSamples(); t++) {
3191 m_surfaceData.variables(id, varIndex, t) = varData(i, m_sampleOffset + t * m_sampleStride);
3192 }
3193 }
3194 }
3195 } else { // ! m_useMergedInputFile -------------------------------------------
3196 TERMM_IF_COND(m_sampleOffset > 0, "Sample offset for multiple input files not supported yet");
3197 TERMM_IF_COND(m_sampleStride > 1, "Sample stride for multiple input files not supported yet");
3198
3199 const MInt noDom = m_noDomainsSurface[surfaceId];
3200 std::vector<MInt> sendCount(noDom);
3201 std::vector<MInt> sendCountNdim(noDom);
3202 std::vector<MInt> displs(noDom);
3203 std::vector<MInt> displsNdim(noDom);
3204 {
3205 std::fill(sendCount.begin(), sendCount.end(), 0);
3206 std::fill(displs.begin(), displs.end(), 0);
3207 sendCount[m_domainIdSurface[surfaceId]] = count;
3208 displs[m_domainIdSurface[surfaceId]] = offset;
3209 MPI_Allreduce(MPI_IN_PLACE, sendCount.data(), sendCount.size(), MPI_INT, MPI_SUM, m_mpiCommSurface[surfaceId],
3210 AT_, "MPI_IN_PLACE", "sendCount");
3211 MPI_Allreduce(MPI_IN_PLACE, displs.data(), displs.size(), MPI_INT, MPI_SUM, m_mpiCommSurface[surfaceId], AT_,
3212 "MPI_IN_PLACE", "displs");
3213 for(MInt i = 0; i < (MInt)sendCount.size(); i++) {
3214 sendCountNdim[i] = sendCount[i] * nDim;
3215 displsNdim[i] = displs[i] * nDim;
3216 }
3217 }
3218 const MInt noTotalCount = std::accumulate(sendCount.begin(), sendCount.end(), 0);
3219
3220 //--Read sortIndex from first input file
3221 std::vector<MInt> sortIndex;
3222 {
3223 auto readSortIndex = [&](const MInt fileNo, std::vector<MInt>& sortIndex_) {
3224 //-Open the correct sample file
3225 const MString fileName = getSurfaceDataFileName(surfaceId, fileNo);
3226 ParallelIo file(fileName, PIO_READ, m_mpiCommSurface[surfaceId]);
3227 //-First read the famous sortIndex_ from first file
3228 const MString varName = "sortIndex";
3229 if(m_domainIdSurface[surfaceId] == 0) {
3230 sortIndex_.resize(noTotalCount);
3231 file.setOffset(noTotalCount, 0);
3232 file.readArray(sortIndex_.data(), varName);
3233 } else {
3234 sortIndex_.resize(0);
3235 file.setOffset(0, 0);
3236 file.readArray(sortIndex_.data(), varName);
3237 }
3238 };
3239 readSortIndex(m_inputFileIndexStart, sortIndex);
3240 // Sanity check: Is sort index the same for all input files?
3241 std::vector<MInt> tmpSortIndex(sortIndex.size());
3242 for(MInt fileNo = 1 + m_inputFileIndexStart; fileNo < m_inputFileIndexEnd + 1; fileNo++) {
3243 readSortIndex(fileNo, tmpSortIndex);
3244 if(!std::equal(sortIndex.begin(), sortIndex.end(), tmpSortIndex.begin())) {
3245 std::stringstream ss;
3246 ss << "SortIndex varies between ";
3248 ss << " and ";
3249 ss << getSurfaceDataFileName(surfaceId, fileNo);
3250 TERMM(1, ss.str());
3251 }
3252 }
3253 }
3254
3255 //--Read geometry data from separate file
3256 {
3257 MFloatScratchSpace measure(count, AT_, "measure");
3258 MFloatScratchSpace coordinates(count * nDim, AT_, "coordinates");
3259 MFloatScratchSpace normalVector(count * nDim, AT_, "normalVector");
3260
3261 //-Read everything from first rank and sort it
3262 const MString varName = "geomMeasure";
3263 const MString baseFileNameSuffix = ".Netcdf";
3264 const MString baseGeometryFileName = "surface_geometryInfo_";
3265 std::ostringstream fileName;
3266 fileName << m_inputDir << baseGeometryFileName << std::to_string(m_surfaceIds[surfaceId]) << baseFileNameSuffix;
3267 ParallelIo file(fileName.str(), PIO_READ, m_mpiCommSurface[surfaceId]);
3268 if(m_domainIdSurface[surfaceId] == 0) {
3269 MFloatScratchSpace sendBuffer(noTotalCount * nDim, AT_, "sendBuffer");
3270 MFloatScratchSpace readBuffer(noTotalCount * nDim, AT_, "readBuffer");
3271 // Read surface area/length
3272 file.setOffset(noTotalCount, 0);
3273 file.readArray(readBuffer.data(), varName);
3274 for(MInt i = 0; i < noTotalCount; i++) {
3275 sendBuffer(i) = readBuffer(sortIndex[i]);
3276 }
3277 MPI_Scatterv(sendBuffer.data(), sendCount.data(), displs.data(), MPI_DOUBLE, measure.data(), count, MPI_DOUBLE,
3278 0, m_mpiCommSurface[surfaceId], AT_, "send", "recv");
3279
3280 // Read coordinates and normal vectors
3281 file.setOffset(noTotalCount * nDim, 0);
3282 file.readArray(readBuffer.data(), "centroid");
3283 for(MInt i = 0; i < noTotalCount; i++) {
3284 for(MInt j = 0; j < nDim; j++) {
3285 sendBuffer(i * nDim + j) = readBuffer(sortIndex[i] * nDim + j);
3286 }
3287 }
3288 MPI_Scatterv(sendBuffer.data(), sendCountNdim.data(), displsNdim.data(), MPI_DOUBLE, coordinates.data(),
3289 count * nDim, MPI_DOUBLE, 0, m_mpiCommSurface[surfaceId], AT_, "send", "recv");
3290 file.readArray(readBuffer.data(), "normalVector");
3291 for(MInt i = 0; i < noTotalCount; i++) {
3292 for(MInt j = 0; j < nDim; j++) {
3293 sendBuffer(i * nDim + j) = readBuffer(sortIndex[i] * nDim + j);
3294 }
3295 }
3296 MPI_Scatterv(sendBuffer.data(), sendCountNdim.data(), displsNdim.data(), MPI_DOUBLE, normalVector.data(),
3297 count * nDim, MPI_DOUBLE, 0, m_mpiCommSurface[surfaceId], AT_, "send", "recv");
3298 //-Scatter data (send)
3299 } else { // not root rank -> receive sorted data
3300 //-Scatter data (receive)
3301 MInt* dummySendBuffer = nullptr;
3302 file.setOffset(0, 0);
3303 file.readArray(dummySendBuffer, varName);
3304 MPI_Scatterv(dummySendBuffer, sendCount.data(), displs.data(), MPI_DOUBLE, measure.data(), count, MPI_DOUBLE, 0,
3305 m_mpiCommSurface[surfaceId], AT_, "send", "recv");
3306 file.readArray(dummySendBuffer, "centroid");
3307 MPI_Scatterv(dummySendBuffer, sendCountNdim.data(), displsNdim.data(), MPI_DOUBLE, coordinates.data(),
3308 count * nDim, MPI_DOUBLE, 0, m_mpiCommSurface[surfaceId], AT_, "send", "recv");
3309 file.readArray(dummySendBuffer, "normalVector");
3310 MPI_Scatterv(dummySendBuffer, sendCountNdim.data(), displsNdim.data(), MPI_DOUBLE, normalVector.data(),
3311 count * nDim, MPI_DOUBLE, 0, m_mpiCommSurface[surfaceId], AT_, "send", "recv");
3312 }
3313
3314 // Create surface elements and store its data in m_surfaceData
3315 createSurfaceElements(surfaceId, measure, coordinates, normalVector);
3316 }
3317
3318 //--Read times only on surface local rank 0 and broadcast to other ranks in this communicator
3319 {
3320 const MString varName = "time";
3321 // const MString varName = "timeStep";
3322 ScratchSpace<MFloat> timesBuffer(m_totalNoSamples, AT_, "timesBuffer");
3323 if(m_domainIdSurface[surfaceId] == 0) {
3324 MInt offsetInBuffer = 0;
3325 for(MInt fileNo = m_inputFileIndexStart; fileNo < m_inputFileIndexEnd + 1; fileNo++) {
3326 // get fileName of fileNo th sample
3327 const MString fileName = getSurfaceDataFileName(surfaceId, fileNo);
3328 ParallelIo file(fileName, PIO_READ, m_mpiCommSurface[surfaceId]);
3329
3330 std::vector<MLong> dims = file.getArrayDims(varName);
3331 const MInt samplesInFile = dims[0];
3332
3333 file.setOffset(samplesInFile, 0);
3334 file.readArray(&timesBuffer[offsetInBuffer], varName);
3335
3336 offsetInBuffer += samplesInFile;
3337 }
3338 // Check the times with those of other surfaces already loaded on this rank (before overwriting them), later
3339 // cross-check the times with all surfaces
3340 if(m_hasTimes) {
3341 for(MInt i = 0; i < noSamples(); i++) {
3342 TERMM_IF_COND(!approx(timesBuffer[m_sampleOffset + i * m_sampleStride], m_times[i], MFloatEps),
3343 "Error: local times for surfaces do not match.");
3344 }
3345 }
3346
3347 // Store times in m_times
3348 if(m_sampleStride == 1) {
3349 std::copy_n(&timesBuffer[m_sampleOffset], noSamples(), &m_times[0]);
3350 } else {
3351 for(MInt i = 0; i < noSamples(); i++) {
3352 m_times[i] = timesBuffer[m_sampleOffset + i * m_sampleStride];
3353 }
3354 }
3355 } else { // not root process
3356 for(MInt fileNo = m_inputFileIndexStart; fileNo < m_inputFileIndexEnd + 1; fileNo++) {
3357 // get fileName of fileNo th sample
3358 const MString fileName = getSurfaceDataFileName(surfaceId, fileNo);
3359 // read only dummy to ensure valid 'parallel' reading
3360 ParallelIo file(fileName, PIO_READ, m_mpiCommSurface[surfaceId]);
3361 file.setOffset(0, 0);
3362 file.readArray(&timesBuffer[0], varName);
3363 }
3364 }
3366 "&m_times[0]");
3367 m_hasTimes = true;
3368 }
3369
3370 //--Read data from each file and sort it correctly into my buffers
3371 {
3372 const MInt noVars = m_inputVars.size();
3373 MInt offsetInBuffer = 0;
3374 for(MInt fileNo = m_inputFileIndexStart; fileNo < m_inputFileIndexEnd + 1; fileNo++) {
3375 //-Open the correct sample file
3376 const MString fileName = getSurfaceDataFileName(surfaceId, fileNo);
3377 ParallelIo file(fileName, PIO_READ, m_mpiCommSurface[surfaceId]);
3378
3379 //-Read variable data
3380 {
3381 // Read data
3382 const MString varName = "pointStates";
3383 file.setOffset(count, offset, 3);
3384
3385 std::vector<MLong> dims = file.getArrayDims(varName);
3386 const MInt samplesInFile = dims[1];
3387
3388 ScratchSpace<MFloat> varData(count, samplesInFile, noVars, AT_, "varData");
3389 file.readArray(varData.data(), varName);
3390
3391 // Create mapping from input variables in file to order of stored variable
3392 std::vector<MInt> varOrder;
3393 {
3394 std::map<MInt, MString> fileVars{};
3395 for(MInt varIndex = 0; varIndex < noVars; varIndex++) {
3396 MString var;
3397 file.getAttribute(&var, "var_" + std::to_string(varIndex), varName);
3398 fileVars[varIndex] = var;
3399 }
3400 for(MInt varIndex = 0; varIndex < noVars; varIndex++) {
3401 varOrder.push_back(m_inputVars[fileVars[varIndex]]);
3402 }
3403 }
3404
3405 // Store in local data
3406 for(MInt i = 0; i < count; i++) {
3407 const MInt id = surfaceOffset + i;
3408 for(MInt t = 0; t < samplesInFile && offsetInBuffer + t < noSamples(); t++) {
3409 for(MInt varIndex = 0; varIndex < noVars; varIndex++) {
3410 const MInt var = varOrder[varIndex];
3411 // TODO labels:ACA add possibility to set a strideA
3412 // TODO labels:ACA add offset, e.g. skip first X samples in files
3413 m_surfaceData.variables(id, var, offsetInBuffer + t) = varData(id, t, varIndex);
3414 }
3415 }
3416 }
3417 offsetInBuffer += samplesInFile;
3418 }
3419 }
3420 }
3421 }
3422}
MBool m_useMergedInputFile
Definition: acasolver.h:305
MInt m_inputFileIndexStart
Definition: acasolver.h:306
std::map< MString, MInt > m_inputVars
Set of input variables.
Definition: acasolver.h:355
MBool m_hasTimes
Definition: acasolver.h:435
MInt m_inputFileIndexEnd
Definition: acasolver.h:307
MString getSurfaceDataFileName(const MInt surfaceId, const MInt fileNo)
IO methods.
Definition: acasolver.cpp:2913
int MPI_Scatterv(const void *sendbuf, const int sendcount[], const int displs[], MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Scatterv

◆ saveObserverSignals()

template<MInt nDim>
void AcaSolver< nDim >::saveObserverSignals
private

Definition at line 2388 of file acasolver.cpp.

2388 {
2389 TRACE();
2390 RECORD_TIMER_START(m_timers[Timers::SaveObserverSignals]);
2391
2392 printMessage("- Save observer signals");
2393
2394 using namespace maia::parallel_io;
2395 const MString fileName = outputDir() + m_outputFilePrefix + "observerData" + ParallelIo::fileExt();
2396
2397 ParallelIo file(fileName, PIO_REPLACE, mpiComm());
2398
2399 ParallelIo::size_type dimSizesCoordinates[] = {globalNoObservers(), nDim};
2400 file.defineArray(PIO_FLOAT, "coordinates", 2, &dimSizesCoordinates[0]);
2401
2402 file.defineArray(PIO_FLOAT, "time", noSamples());
2403 file.defineArray(PIO_FLOAT, "frequency", noSamples());
2404
2405 ParallelIo::size_type dimSizesVarTime[] = {globalNoObservers(), noSamples()};
2406 file.defineArray(PIO_FLOAT, "pressure_time", 2, &dimSizesVarTime[0]);
2407
2408 ParallelIo::size_type dimSizesVarFreq[] = {globalNoObservers(), 2 * noSamples()};
2409 file.defineArray(PIO_FLOAT, "pressure_frequency", 2, &dimSizesVarFreq[0]);
2410
2411 // Store main parameters/configuration as attributes
2412 const MString acousticMethod = (m_acousticMethod == FWH_METHOD) ? "FWH" : "FWH_APE";
2413 file.setAttribute(acousticMethod, "acousticMethod");
2414 file.setAttribute(m_Ma, "Ma");
2415 if(!approx(m_Ma, m_MaDim, MFloatEps)) {
2416 file.setAttribute(m_MaDim, "Ma_dim");
2417 }
2418 file.setAttributes(m_MaVec, "Ma_i", nDim);
2419 // Sample attributes
2420 file.setAttribute(m_noSamples, "noSamples");
2421 file.setAttribute(m_sampleStride, "sampleStride");
2422 file.setAttribute(m_sampleOffset, "sampleOffset");
2423 file.setAttribute(m_dt, "dt");
2424 // Windowing
2425 file.setAttribute(WINDOW::windowNames[m_windowType], "windowType");
2426 file.setAttribute(m_windowNormFactor, "windowNormFactor");
2427 // Surface attributes
2428 for(MInt sId = 0; sId < noSurfaces(); sId++) {
2429 file.setAttribute(m_surfaceInputFileName[sId], "inputFileName_" + std::to_string(m_surfaceIds[sId]));
2430 file.setAttribute(m_noSurfaceElementsGlobal[sId], "noSurfaceElements_" + std::to_string(m_surfaceIds[sId]));
2431 file.setAttribute(m_surfaceWeightingFactor[sId], "surfaceWeight_" + std::to_string(m_surfaceIds[sId]));
2432 }
2433 file.setAttribute(m_observerFileName, "observerFileName");
2434
2435 // Store also observer coordinates to have everything in one file
2436 if(domainId() == 0) {
2437 file.setOffset(globalNoObservers(), 0, 2);
2438 } else {
2439 file.setOffset(0, 0, 2);
2440 }
2441 file.writeArray(m_globalObserverCoordinates.data(), "coordinates");
2442
2443 // write times and frequencies
2444 if(domainId() == 0) {
2445 file.setOffset(noSamples(), 0);
2446 } else {
2447 file.setOffset(0, 0);
2448 }
2449 file.writeArray(&m_times[0], "time");
2450 file.writeArray(&m_frequencies[0], "frequency");
2451
2452 file.setOffset(noObservers(), observerOffset(), 2);
2453 ScratchSpace<MFloat> pressure_time(std::max(noObservers(), 1), noSamples(), AT_, "pressure_time");
2454 for(MInt obs = 0; obs < noObservers(); obs++) {
2455 for(MInt t = 0; t < noSamples(); t++) {
2456 pressure_time(obs, t) = m_observerData.variables(obs, 0, t);
2457 }
2458 }
2459 file.writeArray(&pressure_time[0], "pressure_time");
2460
2461 file.setOffset(noObservers(), observerOffset(), 2);
2462 ScratchSpace<MFloat> pressure_frequency(std::max(noObservers(), 1), 2 * noSamples(), AT_, "pressure_frequency");
2463 for(MInt obs = 0; obs < noObservers(); obs++) {
2464 for(MInt f = 0; f < noSamples(); f++) {
2465 pressure_frequency(obs, 2 * f) = m_observerData.complexVariables(obs, 0, f, 0);
2466 pressure_frequency(obs, 2 * f + 1) = m_observerData.complexVariables(obs, 0, f, 1);
2467 }
2468 }
2469 file.writeArray(&pressure_frequency[0], "pressure_frequency");
2470
2471 RECORD_TIMER_STOP(m_timers[Timers::SaveObserverSignals]);
2472}
MString m_observerFileName
File containing observer points.
Definition: acasolver.h:386
static const std::array< MString, 4 > windowNames
Definition: acasolver.h:544

◆ saveSolverSolution()

template<MInt nDim>
virtual void AcaSolver< nDim >::saveSolverSolution ( const  MBool,
const  MBool 
)
inlinevirtual

Definition at line 117 of file acasolver.h.

117{};

◆ setInputOutputProperties()

template<MInt nDim>
void AcaSolver< nDim >::setInputOutputProperties
private

Definition at line 110 of file acasolver.cpp.

◆ setNumericalProperties()

template<MInt nDim>
void AcaSolver< nDim >::setNumericalProperties
private

Definition at line 424 of file acasolver.cpp.

◆ solutionStep()

template<MInt nDim>
MBool AcaSolver< nDim >::solutionStep
overridevirtual

Reimplemented from Solver.

Definition at line 807 of file acasolver.cpp.

807 {
808 TRACE();
809 RECORD_TIMER_START(m_timers[Timers::Run]);
810
811 // Distribute surface elements among ranks and create separate communicators etc.
813
815
816 // read in data of all surfaces
817 // Note: for validating/testing instead of loading the data from disk you can generate the
818 // analytical input data
820
821 // read in observer points or generate the according to some properties if specified
823
825 // Compute source terms depending on method
827
828 // Compute observer pressure signal by using time or frequency FW-H formulation
830 // apply window to source terms and transform
832
834
835 // Calculate the observer signals in frequency domain
837
838 // backtransformation of local observer signal from frequency into time domain
840 } else if(string2enum(solverMethod()) == MAIA_FWH_TIME) {
841 // Surface Integration
843
845
846 // Windowing and FFT of the observer data
848 }
849
850 // change dimensions from ACA to desired output format
852
853 // output of observer signals (frequency and time domain)
855
856 // perform additional post-processing operations with the observer signals, e.g., compute
857 // RMS-pressure, average over observers, ..., and output the data
859
860 // Calculates the accuracy, the difference between analytic and computed solution. Can be only be
861 // used with analytical data at the moment.
862 // computeAccuracy();
863 } else {
865
866 // Postprocessing with loaded observer data
868 }
869
870 RECORD_TIMER_STOP(m_timers[Timers::Run]);
871
872 m_isFinished = true;
873 return true;
874}
void loadObserverSignals()
Load the observer signals from a file for further postprocessing.
Definition: acasolver.cpp:2477
void initConversionFactors()
Initialize the conversion factors required to convert between.
Definition: acasolver.cpp:4721
void changeDimensionsObserverData()
Definition: acasolver.cpp:4816
MBool m_isFinished
Definition: acasolver.h:286
void postprocessObserverSignals()
Postprocessing of observer signals.
Definition: acasolver.cpp:2531
void calcFrequencies()
Calculate the frequencies.
Definition: acasolver.cpp:1549
void calculateObserverInFrequency()
Calculate the observer signals in frequency domain.
Definition: acasolver.cpp:2294
void windowAndTransformSources()
Apply window function to source terms and transform into frequency domain.
Definition: acasolver.cpp:1253
void saveObserverSignals()
Save the observer signals. Save observer data: 1. pressure data in time domain and 2....
Definition: acasolver.cpp:2388
void calcSourceTerms()
Main compute functions.
Definition: acasolver.cpp:879
void readSurfaceData()
Read the surface data (or generate for an analytical case)
Definition: acasolver.cpp:2925
void initParallelization()
Initialize parallelization (distribution of surface segments on all domains)
Definition: acasolver.cpp:2672
void initObserverPoints()
Initialize observer points.
Definition: acasolver.cpp:4572
void backtransformObservers()
Backtransform the observer frequency signals into the time domain.
Definition: acasolver.cpp:2348
void windowAndTransformObservers()
Apply window function to the observer time series data and transform it into frequency domain.
Definition: acasolver.cpp:1354
void calculateObserverInTime()
Calculate the observer signals in time domain.
Definition: acasolver.cpp:2309

◆ solverConverged()

template<MInt nDim>
MBool AcaSolver< nDim >::solverConverged ( )
inlinevirtual

Reimplemented from Solver.

Definition at line 102 of file acasolver.h.

102{ return m_isFinished; };

◆ storeSurfaceData()

template<MInt nDim>
void AcaSolver< nDim >::storeSurfaceData ( const MInt  surfaceId)
private

Definition at line 3428 of file acasolver.cpp.

3428 {
3429 TRACE();
3430 using namespace maia::parallel_io;
3431 const MString fileName = outputDir() + m_outputFilePrefix + "out_surfaceData_"
3432 + std::to_string(m_surfaceIds[surfaceId]) + ParallelIo::fileExt();
3433 std::stringstream ss;
3434 ss << " "
3435 << "Testing: Storing surface data in " << fileName;
3436 printMessage(ss.str());
3437
3438 ParallelIo file(fileName, PIO_REPLACE, m_mpiCommSurface[surfaceId]);
3439
3440 const MInt totalCount = m_noSurfaceElementsGlobal[surfaceId];
3441 const MInt count = m_noSurfaceElements[surfaceId];
3442 const MInt offset = m_surfaceElementOffsets[surfaceId];
3443
3444 const MString measureName = (nDim == 3) ? "area" : "length";
3445 file.defineArray(PIO_FLOAT, measureName, totalCount);
3446
3447 file.defineArray(PIO_FLOAT, "time", noSamples());
3448
3449 ParallelIo::size_type dimSizesXD[] = {totalCount, nDim};
3450
3451 file.defineArray(PIO_FLOAT, "coordinates", 2, &dimSizesXD[0]);
3452 file.defineArray(PIO_FLOAT, "normalVector", 2, &dimSizesXD[0]);
3453
3454 ParallelIo::size_type dimSizesVar[] = {totalCount, noSamples()};
3455
3456 for(auto& var : m_inputVars) {
3457 const MString varName = var.first;
3458 file.defineArray(PIO_FLOAT, varName, 2, &dimSizesVar[0]);
3459 }
3460
3461 const MInt surfaceOffset = localSurfaceOffset(surfaceId);
3462
3463 // Write surface area/length
3464 file.setOffset(count, offset);
3465 file.writeArray(&m_surfaceData.surfaceArea(surfaceOffset), measureName);
3466
3467 // Write surface area/length
3468 file.setOffset(((m_domainIdSurface[surfaceId] == 0) ? noSamples() : 0), 0);
3469 file.writeArray(&m_times[0], "time");
3470
3471 // Write coordinates and normal vectors
3472 file.setOffset(count, offset, 2);
3473 file.writeArray(&m_surfaceData.surfaceCoordinates(surfaceOffset), "coordinates");
3474 file.writeArray(&m_surfaceData.surfaceNormal(surfaceOffset), "normalVector");
3475
3476 file.setOffset(count, offset, 2);
3477 ScratchSpace<MFloat> varBuffer(count, noSamples(), AT_, "varBuffer");
3478 for(auto& var : m_inputVars) {
3479 const MInt varIndex = var.second;
3480 for(MInt i = 0; i < count; i++) {
3481 for(MInt t = 0; t < noSamples(); t++) {
3482 varBuffer(i, t) = m_surfaceData.variables(surfaceOffset + i, varIndex, t);
3483 }
3484 }
3485
3486 file.writeArray(&varBuffer[0], var.first);
3487 }
3488}

◆ time()

template<MInt nDim>
MFloat AcaSolver< nDim >::time ( ) const
inlineoverridevirtual

Implements Solver.

Definition at line 109 of file acasolver.h.

109 {
110 m_log << "WARNING: Empty body of AcaSolver::time() called" << std::endl;
111 return NAN;
112 }

◆ totalNoSurfaceElements()

template<MInt nDim>
MInt AcaSolver< nDim >::totalNoSurfaceElements ( )
inlineprivate

Definition at line 138 of file acasolver.h.

138{ return std::accumulate(m_noSurfaceElements.begin(), m_noSurfaceElements.end(), 0); }

◆ transformBackToOriginalCoordinate2D()

template<MInt nDim>
void AcaSolver< nDim >::transformBackToOriginalCoordinate2D ( MFloat *const  fX,
MFloat *const  fY 
)
private

Definition at line 2020 of file acasolver.cpp.

2020 {
2021 if(m_zeroFlowAngle) return;
2022
2023 // Back transform to the original coordinate system
2024 // Use negative angular position (-theta) in m_transformationMatrix calculation
2025 const MFloat fX_old = *fX;
2026 const MFloat fY_old = *fY;
2027
2028 *fX = fX_old * m_transformationMatrix[0] - fY_old * m_transformationMatrix[1];
2029 *fY = -fX_old * m_transformationMatrix[2] + fY_old * m_transformationMatrix[3];
2030}
std::array< MFloat, nDim *nDim > m_transformationMatrix
Number of local observer.
Definition: acasolver.h:375
MBool m_zeroFlowAngle
Definition: acasolver.h:376

◆ transformBackToOriginalCoordinate3D()

template<MInt nDim>
void AcaSolver< nDim >::transformBackToOriginalCoordinate3D ( MFloat *const  fX,
MFloat *const  fY,
MFloat *const  fZ 
)
private

Definition at line 2033 of file acasolver.cpp.

2033 {
2034 if(m_zeroFlowAngle) return;
2035
2036 // Back transform to the original coordinate system
2037 // Use negative angular position (-alpha) and (-theta) in m_transformationMatrix calculation
2038 const MFloat fX_old = *fX;
2039 const MFloat fY_old = *fY;
2040 const MFloat fZ_old = *fZ;
2041
2042 *fX = fX_old * m_transformationMatrix[0] - fY_old * m_transformationMatrix[1] - fZ_old * m_transformationMatrix[2];
2043 *fY = -fX_old * m_transformationMatrix[3] + fY_old * m_transformationMatrix[4] + fZ_old * m_transformationMatrix[5];
2044 *fZ = -fX_old * m_transformationMatrix[6] + fY_old * m_transformationMatrix[7] + fZ_old * m_transformationMatrix[8];
2045}

◆ transformCoordinatesToFlowDirection2D()

template<MInt nDim>
void AcaSolver< nDim >::transformCoordinatesToFlowDirection2D ( MFloat *const  fX,
MFloat *const  fY 
)
private

Definition at line 1994 of file acasolver.cpp.

1994 {
1995 if(m_zeroFlowAngle) return;
1996
1997 // Project the vector on the flow direction U_inf = (U_inf, 0)
1998 const MFloat fX_old = *fX;
1999 const MFloat fY_old = *fY;
2000
2001 *fX = fX_old * m_transformationMatrix[0] + fY_old * m_transformationMatrix[1];
2002 *fY = fX_old * m_transformationMatrix[2] + fY_old * m_transformationMatrix[3];
2003}

◆ transformCoordinatesToFlowDirection3D()

template<MInt nDim>
void AcaSolver< nDim >::transformCoordinatesToFlowDirection3D ( MFloat *const  fX,
MFloat *const  fY,
MFloat *const  fZ 
)
private

Definition at line 2006 of file acasolver.cpp.

2006 {
2007 if(m_zeroFlowAngle) return;
2008
2009 // Project the vector on the flow direction U_inf = (U_inf, 0, 0)
2010 const MFloat fX_old = *fX;
2011 const MFloat fY_old = *fY;
2012 const MFloat fZ_old = *fZ;
2013
2014 *fX = fX_old * m_transformationMatrix[0] + fY_old * m_transformationMatrix[1] + fZ_old * m_transformationMatrix[2];
2015 *fY = fX_old * m_transformationMatrix[3] + fY_old * m_transformationMatrix[4] + fZ_old * m_transformationMatrix[5];
2016 *fZ = fX_old * m_transformationMatrix[6] + fY_old * m_transformationMatrix[7] + fZ_old * m_transformationMatrix[8];
2017}

◆ windowAndTransformObservers()

template<MInt nDim>
void AcaSolver< nDim >::windowAndTransformObservers
private

Definition at line 1354 of file acasolver.cpp.

1354 {
1355 TRACE();
1356
1357 // Compute the window function factors and the normalization factor
1358 std::vector<MFloat> window(noSamples());
1359 std::fill(window.begin(), window.end(), 1.0);
1360 calcWindowFactors(window.data());
1361
1362 const MFloat noSamplesF = static_cast<MFloat>(noSamples());
1363 for(MInt observerId = 0; observerId < noObservers(); observerId++) {
1364 // Sum up observer pressure over all samples
1365 MFloat sumObsPressure = 0.0;
1366 for(MInt t = 0; t < noSamples(); t++) {
1367 sumObsPressure += m_observerData.variables(observerId, 0, t);
1368 }
1369 const MFloat aveObsPressure = sumObsPressure / noSamplesF; // Compute average
1370
1371 // Substract average from all samples to get the fluctuations
1372 // After substracting the mean apply the window function [see e.g. Mendez et al. or Lockard]
1373 // copy variables into complex variables array: re1, im1, re2, im2, re3, im3, ... with im_n = 0
1374 for(MInt t = 0; t < noSamples(); t++) {
1375 // Do nothing to "m_observerData.variables" output the original data
1376 m_observerData.complexVariables(observerId, 0, t, 0) =
1377 window[t] * (m_observerData.variables(observerId, 0, t) - aveObsPressure); // Real part
1378 m_observerData.complexVariables(observerId, 0, t, 1) = 0.0; // Imaginary part
1379 }
1380
1381 // Use FFT or DFT to transform source terms (depending on possibility and the set property)
1383 if(m_FastFourier == true && m_transformationType == 1) {
1384 FastFourierTransform(&m_observerData.complexVariables(observerId, 0), noSamples(), 1, nullptr, true);
1385 } else if(m_FastFourier == false || (m_FastFourier == true && m_transformationType == 0)) {
1386 // 1 in function means forward; -1 is backward
1387 DiscreteFourierTransform(&m_observerData.complexVariables(observerId, 0), noSamples(), 1, nullptr, true);
1388 } else {
1389 TERMM(1, "Error Fourier-Transform: Check transformationType and noSamples.");
1390 }
1391
1392 // Normalize for conservation of energy
1393 for(MInt t = 0; t < noSamples(); t++) {
1394 m_observerData.complexVariables(observerId, 0, t, 0) *= m_windowNormFactor;
1395 m_observerData.complexVariables(observerId, 0, t, 1) *= m_windowNormFactor;
1396 }
1397 } // End of observer loop
1398}
void checkNoSamplesPotencyOfTwo()
Definition: acasolver.cpp:4864
void calcWindowFactors(MFloat *const p_window)
Compute the window function factors and the normalization factor.
Definition: acasolver.cpp:1195

◆ windowAndTransformSources()

template<MInt nDim>
void AcaSolver< nDim >::windowAndTransformSources
private

Definition at line 1253 of file acasolver.cpp.

1253 {
1254 TRACE();
1255 RECORD_TIMER_START(m_timers[Timers::WindowAndTransformSources]);
1256 printMessage("- Window and transform source terms");
1257
1258 // Compute the window function factors and the normalization factor
1259 std::vector<MFloat> window(noSamples());
1260 std::fill(window.begin(), window.end(), 1.0);
1261 calcWindowFactors(window.data());
1262
1263 // Set source term indices depending on used method
1264 std::vector<MInt> VarDim;
1265 std::vector<MInt> VarDimC;
1267 if constexpr(nDim == 3) {
1268 VarDim = {FWH::FX, FWH::FY, FWH::FZ, FWH::Q};
1269 VarDimC = {FWH::FX_C, FWH::FY_C, FWH::FZ_C, FWH::Q_C};
1270 } else {
1271 VarDim = {FWH::FX, FWH::FY, FWH::Q};
1272 VarDimC = {FWH::FX_C, FWH::FY_C, FWH::Q_C};
1273 }
1274 } else if(m_acousticMethod == FWH_APE_METHOD) {
1275 if constexpr(nDim == 3) {
1278 } else {
1279 VarDim = {FWH_APE::FX, FWH_APE::FY, FWH_APE::Q};
1281 }
1282 } else {
1283 TERMM(1, "Unknown acoustic method.");
1284 }
1285
1286 MInt noSourceTerms = 0;
1287 if constexpr(nDim == 3) {
1288 noSourceTerms = 4;
1289 } else if constexpr(nDim == 2) {
1290 noSourceTerms = 3;
1291 }
1292
1293 const MFloat noSamplesF = static_cast<MFloat>(noSamples());
1294 for(MInt segmentId = 0; segmentId < totalNoSurfaceElements(); segmentId++) {
1295 for(MInt i = 0; i < noSourceTerms; i++) {
1296 // Sum up source term over all samples
1297 MFloat sumSource = 0.0;
1298 for(MInt t = 0; t < noSamples(); t++) {
1299 sumSource += m_surfaceData.variables(segmentId, VarDim[i], t);
1300 }
1301 const MFloat avgSource = sumSource / noSamplesF; // Compute average
1302
1303 // Substract average from all samples to get the fluctuations
1304 // After substracting the mean apply the window function [see e.g. Mendez et al. or Lockard]
1305 for(MInt t = 0; t < noSamples(); t++) {
1306 m_surfaceData.variables(segmentId, VarDim[i], t) -= avgSource;
1307 m_surfaceData.variables(segmentId, VarDim[i], t) *= window[t];
1308 }
1309 }
1310
1311 // Copy variables into complex variables array: Re1, Im1, Re2, Im2, Re3, Im3, ... with Im_n = 0
1312 for(MInt i = 0; i < noSourceTerms; i++) {
1313 for(MInt t = 0; t < noSamples(); t++) {
1314 m_surfaceData.complexVariables(segmentId, VarDimC[i], t, 0) =
1315 m_surfaceData.variables(segmentId, VarDim[i], t); // Real part
1316 m_surfaceData.complexVariables(segmentId, VarDimC[i], t, 1) = 0.0; // Imaginary part
1317 }
1318 }
1319
1320 // Use FFT or DFT to transform source terms (depending on possibility and the set property)
1322 if(m_FastFourier == true && m_transformationType == 1) {
1323 for(MInt i = 0; i < noSourceTerms; i++) {
1324 FastFourierTransform(&m_surfaceData.complexVariables(segmentId, VarDimC[i]), noSamples(), 1, nullptr, true);
1325 }
1326 } else if(m_FastFourier == false || (m_FastFourier == true && m_transformationType == 0)) {
1327 for(MInt i = 0; i < noSourceTerms; i++) {
1328 // 1 in function means forward; -1 is backward
1329 DiscreteFourierTransform(&m_surfaceData.complexVariables(segmentId, VarDimC[i]), noSamples(), 1, nullptr, true);
1330 }
1331 } else {
1332 TERMM(1, "Error Fourier-Transform: Check transformationType and noSamples.");
1333 }
1334
1335 // Normalize for conservation of energy
1336 for(MInt t = 0; t < noSamples(); t++) {
1337 for(MInt i = 0; i < noSourceTerms; i++) {
1338 m_surfaceData.complexVariables(segmentId, VarDimC[i], t, 0) *= m_windowNormFactor;
1339 m_surfaceData.complexVariables(segmentId, VarDimC[i], t, 1) *= m_windowNormFactor;
1340 }
1341 }
1342
1343 // Calculate frequencies is moved out of segmentId Loop because it is the same for every
1344 // segmentId. Moved to calcSurfaceIntegral Calculate time: It is calculated at
1345 // "generateSurfaceData" m_times = dt * noSamples() Initialize observerdata array. Function
1346 // initObserverPoints
1347 } // End of loop over all segments
1348
1349 RECORD_TIMER_STOP(m_timers[Timers::WindowAndTransformSources]);
1350}

Member Data Documentation

◆ m_aca2Output

template<MInt nDim>
struct AcaSolver::ConversionFactors AcaSolver< nDim >::m_aca2Output
private

◆ m_acaPostprocessingFile

template<MInt nDim>
MString AcaSolver< nDim >::m_acaPostprocessingFile = ""
private

Definition at line 442 of file acasolver.h.

◆ m_acaPostprocessingMode

template<MInt nDim>
MBool AcaSolver< nDim >::m_acaPostprocessingMode = false
private

Definition at line 441 of file acasolver.h.

◆ m_acaResultsNondimMode

template<MInt nDim>
MInt AcaSolver< nDim >::m_acaResultsNondimMode = 0
private

Definition at line 288 of file acasolver.h.

◆ m_acousticMethod

template<MInt nDim>
MInt AcaSolver< nDim >::m_acousticMethod = -1
private

Definition at line 347 of file acasolver.h.

◆ m_allowMultipleSurfacesPerRank

template<MInt nDim>
MBool AcaSolver< nDim >::m_allowMultipleSurfacesPerRank = false
private

Definition at line 313 of file acasolver.h.

◆ m_Analyticfreq

template<MInt nDim>
std::vector<MFloat> AcaSolver< nDim >::m_Analyticfreq {}
private

Definition at line 412 of file acasolver.h.

◆ m_cInfty

template<MInt nDim>
MFloat AcaSolver< nDim >::m_cInfty = -1.0
private

Definition at line 408 of file acasolver.h.

◆ m_domainIdSurface

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_domainIdSurface {}
private

Definition at line 326 of file acasolver.h.

◆ m_dt

template<MInt nDim>
MFloat AcaSolver< nDim >::m_dt = -1.0
private

Definition at line 418 of file acasolver.h.

◆ m_FastFourier

template<MInt nDim>
MBool AcaSolver< nDim >::m_FastFourier = false
private

Definition at line 430 of file acasolver.h.

◆ m_frequencies

template<MInt nDim>
std::vector<MFloat> AcaSolver< nDim >::m_frequencies {}
private

Definition at line 434 of file acasolver.h.

◆ m_fwhMeanStateType

template<MInt nDim>
MInt AcaSolver< nDim >::m_fwhMeanStateType = 0
private

Definition at line 349 of file acasolver.h.

◆ m_fwhTimeShiftType

template<MInt nDim>
MInt AcaSolver< nDim >::m_fwhTimeShiftType = 0
private

Definition at line 348 of file acasolver.h.

◆ m_gamma

template<MInt nDim>
constexpr MFloat AcaSolver< nDim >::m_gamma = 1.4
staticconstexprprivate

Definition at line 427 of file acasolver.h.

◆ m_generateObservers

template<MInt nDim>
MBool AcaSolver< nDim >::m_generateObservers = false
private

Definition at line 388 of file acasolver.h.

◆ m_generateSurfaceData

template<MInt nDim>
MBool AcaSolver< nDim >::m_generateSurfaceData = false
private

Definition at line 392 of file acasolver.h.

◆ m_globalObserverCoordinates

template<MInt nDim>
std::vector<MFloat> AcaSolver< nDim >::m_globalObserverCoordinates
private

Definition at line 368 of file acasolver.h.

◆ m_hasTimes

template<MInt nDim>
MBool AcaSolver< nDim >::m_hasTimes = false
private

Definition at line 435 of file acasolver.h.

◆ m_input2Aca

template<MInt nDim>
struct AcaSolver::ConversionFactors AcaSolver< nDim >::m_input2Aca
private

◆ m_inputDir

template<MInt nDim>
MString AcaSolver< nDim >::m_inputDir
private

Definition at line 379 of file acasolver.h.

◆ m_inputFileIndexEnd

template<MInt nDim>
MInt AcaSolver< nDim >::m_inputFileIndexEnd
private

Definition at line 307 of file acasolver.h.

◆ m_inputFileIndexStart

template<MInt nDim>
MInt AcaSolver< nDim >::m_inputFileIndexStart
private

Definition at line 306 of file acasolver.h.

◆ m_inputVars

template<MInt nDim>
std::map<MString, MInt> AcaSolver< nDim >::m_inputVars {}
private

Definition at line 355 of file acasolver.h.

◆ m_isFinished

template<MInt nDim>
MBool AcaSolver< nDim >::m_isFinished = false
private

Member variables Solver status

Definition at line 286 of file acasolver.h.

◆ m_lambdaMach

template<MInt nDim>
MFloat AcaSolver< nDim >::m_lambdaMach = -1.0
private

Definition at line 405 of file acasolver.h.

◆ m_lambdaZero

template<MInt nDim>
MFloat AcaSolver< nDim >::m_lambdaZero = -1.0
private

Definition at line 404 of file acasolver.h.

◆ m_Ma

template<MInt nDim>
MFloat AcaSolver< nDim >::m_Ma = -1.0
private

Definition at line 423 of file acasolver.h.

◆ m_MaDim

template<MInt nDim>
MFloat AcaSolver< nDim >::m_MaDim = -1.0
private

Definition at line 425 of file acasolver.h.

◆ m_MaVec

template<MInt nDim>
MFloat AcaSolver< nDim >::m_MaVec[3]
private

Definition at line 421 of file acasolver.h.

◆ m_mpiCommSurface

template<MInt nDim>
std::vector<MPI_Comm> AcaSolver< nDim >::m_mpiCommSurface {}
private

Definition at line 322 of file acasolver.h.

◆ m_noComplexVariables

template<MInt nDim>
MInt AcaSolver< nDim >::m_noComplexVariables = -1
private

Definition at line 352 of file acasolver.h.

◆ m_noDomainsSurface

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_noDomainsSurface {}
private

Definition at line 324 of file acasolver.h.

◆ m_noGlobalObservers

template<MInt nDim>
MInt AcaSolver< nDim >::m_noGlobalObservers = -1
private

Definition at line 366 of file acasolver.h.

◆ m_noObservers

template<MInt nDim>
MInt AcaSolver< nDim >::m_noObservers = 0
private

Definition at line 372 of file acasolver.h.

◆ m_noPostprocessingOps

template<MInt nDim>
MInt AcaSolver< nDim >::m_noPostprocessingOps = 0
private

Definition at line 438 of file acasolver.h.

◆ m_noSamples

template<MInt nDim>
MInt AcaSolver< nDim >::m_noSamples = -1
private

Definition at line 335 of file acasolver.h.

◆ m_noSurfaceElements

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_noSurfaceElements {}
private

Definition at line 310 of file acasolver.h.

◆ m_noSurfaceElementsGlobal

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_noSurfaceElementsGlobal {}
private

Definition at line 316 of file acasolver.h.

◆ m_noSurfaces

template<MInt nDim>
MInt AcaSolver< nDim >::m_noSurfaces = -1
private

Definition at line 301 of file acasolver.h.

◆ m_noVariables

template<MInt nDim>
MInt AcaSolver< nDim >::m_noVariables = -1
private

Definition at line 351 of file acasolver.h.

◆ m_observerData

template<MInt nDim>
ObserverDataCollector AcaSolver< nDim >::m_observerData
private

Definition at line 369 of file acasolver.h.

◆ m_observerFileName

template<MInt nDim>
MString AcaSolver< nDim >::m_observerFileName
private

Definition at line 386 of file acasolver.h.

◆ m_offsetObserver

template<MInt nDim>
MInt AcaSolver< nDim >::m_offsetObserver = 0
private

Definition at line 371 of file acasolver.h.

◆ m_omega_factor

template<MInt nDim>
MFloat AcaSolver< nDim >::m_omega_factor = -1.0
private

Definition at line 401 of file acasolver.h.

◆ m_outputFilePrefix

template<MInt nDim>
MString AcaSolver< nDim >::m_outputFilePrefix = ""
private

Definition at line 380 of file acasolver.h.

◆ m_post

template<MInt nDim>
std::vector<std::unique_ptr<AcaPostProcessing> > AcaSolver< nDim >::m_post
private

Definition at line 272 of file acasolver.h.

◆ m_postprocessingOps

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_postprocessingOps {}
private

Definition at line 439 of file acasolver.h.

◆ m_rhoInfty

template<MInt nDim>
MFloat AcaSolver< nDim >::m_rhoInfty = -1.0
private

Definition at line 409 of file acasolver.h.

◆ m_rmsP_Analytic

template<MInt nDim>
std::vector<MFloat> AcaSolver< nDim >::m_rmsP_Analytic {}
private

Definition at line 415 of file acasolver.h.

◆ m_sampleOffset

template<MInt nDim>
MInt AcaSolver< nDim >::m_sampleOffset = 0
private

Definition at line 341 of file acasolver.h.

◆ m_sampleStride

template<MInt nDim>
MInt AcaSolver< nDim >::m_sampleStride = 1
private

Definition at line 339 of file acasolver.h.

◆ m_sourceParameters

template<MInt nDim>
maia::acoustic::SourceParameters AcaSolver< nDim >::m_sourceParameters
private

Definition at line 398 of file acasolver.h.

◆ m_sourceType

template<MInt nDim>
MInt AcaSolver< nDim >::m_sourceType = -1
private

Definition at line 395 of file acasolver.h.

◆ m_storeSurfaceData

template<MInt nDim>
MBool AcaSolver< nDim >::m_storeSurfaceData = false
private

Enable storing of surface data (testing or output of generated data)

Definition at line 383 of file acasolver.h.

◆ m_surfaceData

template<MInt nDim>
SurfaceDataCollector AcaSolver< nDim >::m_surfaceData
private

Definition at line 344 of file acasolver.h.

◆ m_surfaceElementOffsets

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_surfaceElementOffsets {}
private

Definition at line 319 of file acasolver.h.

◆ m_surfaceIds

template<MInt nDim>
std::vector<MInt> AcaSolver< nDim >::m_surfaceIds {}
private

Definition at line 303 of file acasolver.h.

◆ m_surfaceInputFileName

template<MInt nDim>
std::vector<MString> AcaSolver< nDim >::m_surfaceInputFileName {}
private

Definition at line 332 of file acasolver.h.

◆ m_surfaceWeightingFactor

template<MInt nDim>
std::vector<MFloat> AcaSolver< nDim >::m_surfaceWeightingFactor {}
private

Definition at line 329 of file acasolver.h.

◆ m_symBc

template<MInt nDim>
std::vector<AcaSymBc> AcaSolver< nDim >::m_symBc
private

Definition at line 558 of file acasolver.h.

◆ m_timerGroup

template<MInt nDim>
MInt AcaSolver< nDim >::m_timerGroup = -1
private

Definition at line 446 of file acasolver.h.

◆ m_timers

template<MInt nDim>
std::array<MInt, Timers::_count> AcaSolver< nDim >::m_timers {}
private

Definition at line 448 of file acasolver.h.

◆ m_times

template<MInt nDim>
std::vector<MFloat> AcaSolver< nDim >::m_times {}
private

Definition at line 433 of file acasolver.h.

◆ m_totalNoSamples

template<MInt nDim>
MInt AcaSolver< nDim >::m_totalNoSamples = -1
private

Definition at line 337 of file acasolver.h.

◆ m_transformationMatrix

template<MInt nDim>
std::array<MFloat, nDim * nDim> AcaSolver< nDim >::m_transformationMatrix
private

Coordinate system transformation

Definition at line 375 of file acasolver.h.

◆ m_transformationType

template<MInt nDim>
MInt AcaSolver< nDim >::m_transformationType = 0
private

Definition at line 363 of file acasolver.h.

◆ m_useMergedInputFile

template<MInt nDim>
MBool AcaSolver< nDim >::m_useMergedInputFile
private

Definition at line 305 of file acasolver.h.

◆ m_windowNormFactor

template<MInt nDim>
MFloat AcaSolver< nDim >::m_windowNormFactor = -1.0
private

Definition at line 360 of file acasolver.h.

◆ m_windowType

template<MInt nDim>
MInt AcaSolver< nDim >::m_windowType = 0
private

Definition at line 358 of file acasolver.h.

◆ m_zeroFlowAngle

template<MInt nDim>
MBool AcaSolver< nDim >::m_zeroFlowAngle = false
private

Definition at line 376 of file acasolver.h.


The documentation for this class was generated from the following files: