Correct way to extract Harmonic Response Frequency Results

mgoldgruber
mgoldgruber Member, Employee Posts: 1 ✭✭✭
edited August 2024 in Structures

When extracting Frequency Response Results with PyMechanical the order of operations performed on the real and imaginary parts to calculate the amplitude is important. Analogous to vector operations, accumulating the real and imaginary components separately, before combining them to calculate the amplitude is mandatory.
This might sound obvious, but doing the amplitude calculation first and then the accumulation and averaging, is a trap that is easy to fall into.

def after_post(this, solution):# Do not edit this line
    """
    Called after post processing.
    Keyword Arguments : 
        this -- the datamodel object instance of the python code object you are currently editing in the tree
        solution -- Solution
    """

    import os
    import wbjn
    import Ans.DataProcessing as dpf

    # RESULTS FILE NAME
    myResName = 'Freq_amp'
    dpn = wbjn.ExecuteCommand(ExtAPI,"returnValue(a+Parameters.GetActiveDesignPoint().Name)",a="DP")
    projectDir = wbjn.ExecuteCommand(ExtAPI,"returnValue(GetUserFilesDirectory())")
    filePath = os.path.join(projectDir,dpn + '_' + myResName + '.txt')
    if os.path.isfile(filePath):
        os.remove(filePath) #Remove old file if exists

    # DEFINE DATASOURCE --> .RST/.RTH
    dataSource = dpf.DataSources(solution.Parent.ResultFileName) # Use in Tree for solution

    # GET TIMESTEPS OR FREQUENCIES
    freqlist = dpf.operators.metadata.time_freq_provider(data_sources=dataSource).outputs.gettime_freq_support().TimeFreqs.Data

    # GET RESULT FIELD CONTAINER (e.g. Acceleration in Z direction)
    ACC_Z = dpf.operators.result.acceleration_Z(time_scoping=freqlist, data_sources=dataSource).outputs.getfields_container()

    # OPERATE ON RESULT
    # 1. Calculate Accumulated results component-wise (real, imaginary) over all nodes
    accum = dpf.operators.math.accumulate_fc(fields_container=ACC_Z)
    # 2. Calculate Average over all Nodes
    avg = dpf.operators.math.scale_fc(fields_container=accum, ponderation=1.0/ACC_Z[0].ElementaryDataCount)
    # 3. Calculate Amplitude of Real/Imaginary Data
    amp = dpf.operators.math.amplitude_fc(fields_container=avg)

    #WRITE TO FILE
    with open(filePath,'w') as f:
        # write column headers
        f.write( 'Frequency, Amplitude')
        f.write('\n')
        for i, freq in enumerate(freqlist):
            f.write( str(freq) + ', ' + str(amp.outputs.getfields_container()[i].Data[0]) )
            f.write('\n')
    pass