NREL / pCrunch

Apache License 2.0
8 stars 11 forks source link

Bug in parallel processing of outputs and magnitude channels? #20

Open KlootwijkBart opened 1 year ago

KlootwijkBart commented 1 year ago

Dear developing team,

I am trying to use the pCrunch tools to post-process a bunch of DLCs from OpenFAST runs in Python. However, I am encountering some problems. I installed the latest release through conda, as explained in the README. Following the example.ipynb script, I set up my script as follows. Please find my questions below.

outputs = load_FAST_out(outfiles) # outfiles is a list containing 56 *.outb files

magnitude_channels = {
    "RootMc1": ["RootMxc1", "RootMyc1", "RootMzc1"]}

fatigue_channels = {
    "RootMc1": FatigueParams(lifetime=25.0, slope=10.0, ult_stress=6e8)}

channel_extremes = [
    "RotSpeed",
    "RotThrust",
    "RotTorq",
    "RootMc1"]

la = LoadsAnalysis(outputs,                          
                   magnitude_channels=magnitude_channels,  
                   fatigue_channels=fatigue_channels,      
                   extreme_channels=channel_extremes,      
                   trim_data=(400,) # data is trimmed to (tmin, tmax(optional))
                   )

la.process_outputs(cores=1)  

1) My first question deals with the magnitude_channels parameter. I understand from the context that it combines the vector components of e.g. a force vector, and returns the magnitude of the force. In the example script, the moment components RootMxc1, RootMyc1 and RootMzc1 together make up the magnitude RootMc1, which is then passed to the fatigue_channels. However, when I do this, I get the following warning after running la.process_outputs(): Channel 'RootMc1' not included in DEL calculation. Also, when I call enter la.summary_stats['RootMc1'] in the console, I get a KeyError. Could you please clarify what the magnitude channel should do, and whether I misunderstand its use?

When I change the fatigue_channels to a dictionary containing the moment components instead of the magnitude, it runs as expected:

fatigue_channels = {
    "RootMxc1": FatigueParams(lifetime=25.0, slope=10.0, ult_stress=6e8),
    "RootMyc1": FatigueParams(lifetime=25.0, slope=10.0, ult_stress=6e8),
    "RootMzc1": FatigueParams(lifetime=25.0, slope=10.0, ult_stress=6e8)}

2) The first few times I tried to run the script using multiple cores. However, it seems to hang when parallel processing is enabled. When I use serial post-processing, the script takes about 45 seconds to run and finishes successfully. Using parallel processing, however, the program still didn't return anything after half an hour. For me, currently the time it takes to perform serial processing is acceptable, but it would be handy to make use of the parallel processing capability in the future. Is this a bug that you are aware of?

3) Lastly, I am most interested in calculating the fatigue damage. Could you please provide some guidance as to how this is done using pCrunch? The DELs seem fine, but when I enter la.damage in the console, all I get are NaNs:

image

I look forward to your help.

Best,

gbarter commented 1 year ago

Hello @KlootwijkBart ,

Thank you for the careful documentation of all of these issues and your patience in waiting for my reply. You indeed caught some bugs and other inadequacies in our examples. I have pushed a new release of fixes. To address your points:

  1. I think the reason your vector magnitude summaries were not propagating all of the way through is due to the call of la = LoadsAnalysis(outputs, instead of la = LoadsAnalysis(outfiles,. The outputs = load_FAST_out(outfiles) was done without awareness of the vector magnitude outputs, but if you pass in the output file strings, they will be read with awareness of those new channels. Does that make sense?
  2. I had to do some Googling here. The Python multiprocessing must be run from a script under a if __name__ == "__main__" instance. Once I tried this in the post_BatchRun.py example, passing in multiple cores via la.process_outputs(cores=3, ... worked fine. Without that, then there were some abstruse errors. I am still fuzzy on how this works in a Jupyter environment, but it seems to be okay there. Let me know if this fix works for you.
  3. The examples were admittedly inadequate here. There are additional flag arguments that must be passed to activate the Palmer-Miner damage calculation. Less one poured over the source code, that was not obvious. This is fixed now in both the Jupyter and script examples.

Cheers, Garrett

KlootwijkBart commented 1 year ago

Hi @gbarter

Thank you for clarifying and adjusting the examples. I implemented the changes and everything works as expected now.

Best,