From 28fbefdb74ee970a6210bb0abd032f8986829b0b Mon Sep 17 00:00:00 2001 From: Mayank Chetan Date: Tue, 1 Apr 2025 09:39:45 -0600 Subject: [PATCH 1/3] Updating missing copyright year and owner --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 8dada3edaf..3b43f8bbe7 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2025 NREL Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 6c3deb5595229d764e51abd1e6c448cb4519345d Mon Sep 17 00:00:00 2001 From: Mayank Chetan Date: Fri, 17 Jul 2026 13:15:50 -0600 Subject: [PATCH 2/3] fix(glue): write linearization (.lin) output at full precision regardless of OutFmt The .lin Jacobian matrices (A/B/C/D, dUdu/dUdy/dXdy/J and the module-level blocks), the operating-point column, and the header values (incl. Rotor Speed, consumed by MBC3 tools) were formatted with the deck's tabular OutFmt, whose default "ES10.3E2" carries ~4 significant digits. Assembled Jacobians of coupled-section BeamDyn blades span ~15 orders of magnitude, so the write itself corrupted downstream eigenanalysis: physically impossible results (spurious positive real eigenvalues, negative damping ratios, merged or missing tower modes) for parked, passive structures on IEA-15/3.4/10/22 class models, while near-diagonal-section models (NREL 5-MW) escaped. Fix: a fixed module-level format LinFmt='ES24.15E3' (full double precision) for all numeric .lin output in FAST_ModGlue; tab-stop width updated to match. Tabular time-series output keeps honoring OutFmt, unchanged. Verification: IEA-15-240-RWT structure-only standstill case with default OutFmt, patched dev build: A-matrix eigenvalues go from 1 spurious positive real eigenvalue + merged tower mode (0.2163 Hz) to 0 unstable and a correctly split tower pair (0.2369/0.2386 Hz vs ElastoDyn 0.2350/0.2366); identical to the ES18.9E3-deck control on the unpatched binary. Rounding a clean A to 4 significant digits in numpy reproduces the corrupted eigenvalues exactly, confirming the mechanism. Co-Authored-By: Claude Fable 5 --- modules/openfast-library/src/FAST_ModGlue.f90 | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/modules/openfast-library/src/FAST_ModGlue.f90 b/modules/openfast-library/src/FAST_ModGlue.f90 index 645ca2626d..2fa3d142bf 100644 --- a/modules/openfast-library/src/FAST_ModGlue.f90 +++ b/modules/openfast-library/src/FAST_ModGlue.f90 @@ -42,6 +42,14 @@ module FAST_ModGlue logical :: CalcSteadyDebug = .false. +! Numeric format for linearization (.lin) file output. Fixed at full double +! precision independent of the deck's tabular OutFmt: the .lin matrices feed +! eigenanalysis, and Jacobians of coupled-section blades span ~15 orders of +! magnitude, so truncated writes (e.g. the ES10.3E2 default) corrupt their +! eigenvalues. +character(*), parameter :: LinFmt = 'ES24.15E3' +integer(IntKi), parameter :: LinFmtWidth = 24 + contains subroutine ModGlue_CombineModules(ModGlue, ModDataAry, Mappings, iModAry, FlagFilter, Linearize, ErrStat, ErrMsg, Name) @@ -1399,7 +1407,7 @@ subroutine ModGlue_CalcWriteLinearMatrices(Vars, Lin, p_FAST, y_FAST, t_global, write (Un, '(A)') 'Simulation information:' - fmt = '(3x,A,1x,'//trim(p_FAST%OutFmt_t)//',1x,A)' + fmt = '(3x,A,1x,'//LinFmt//',1x,A)' Desc = 'Simulation time:'; write (Un, fmt) Desc, t_global, 's' Desc = 'Rotor Speed: '; write (Un, fmt) Desc, y_FAST%Lin%RotSpeed, 'rad/s' Desc = 'Azimuth: '; write (Un, fmt) Desc, y_FAST%Lin%Azimuth, 'rad' @@ -1472,15 +1480,15 @@ subroutine ModGlue_CalcWriteLinearMatrices(Vars, Lin, p_FAST, y_FAST, t_global, ! If Jacobian matrix output is requested if (FullOutputLoc) then write (Un, '(/,A,/)') 'Jacobian matrices:' - if (allocated(Lin%dUdu)) call WrPartialMatrix(Lin%dUdu, Un, p_FAST%OutFmt, 'dUdu', UseRow=uUse, UseCol=uUse) - if (allocated(Lin%dUdy)) call WrPartialMatrix(Lin%dUdy, Un, p_FAST%OutFmt, 'dUdy', UseRow=uUse, UseCol=yUse) - if (allocated(Lin%dXdy)) call WrPartialMatrix(Lin%dXdy, Un, p_FAST%OutFmt, 'dXdy', UseRow=xUse, UseCol=yUse) - if (allocated(Lin%J)) call WrPartialMatrix(Lin%J, Un, p_FAST%OutFmt, 'J') + if (allocated(Lin%dUdu)) call WrPartialMatrix(Lin%dUdu, Un, LinFmt, 'dUdu', UseRow=uUse, UseCol=uUse) + if (allocated(Lin%dUdy)) call WrPartialMatrix(Lin%dUdy, Un, LinFmt, 'dUdy', UseRow=uUse, UseCol=yUse) + if (allocated(Lin%dXdy)) call WrPartialMatrix(Lin%dXdy, Un, LinFmt, 'dXdy', UseRow=xUse, UseCol=yUse) + if (allocated(Lin%J)) call WrPartialMatrix(Lin%J, Un, LinFmt, 'J') if (present(ModSuffix)) then - if (allocated(Lin%dXdx)) call WrPartialMatrix(Lin%dXdx, Un, p_FAST%OutFmt, 'dXdx', UseRow=xUse, UseCol=xUse) - if (allocated(Lin%dXdu)) call WrPartialMatrix(Lin%dXdu, Un, p_FAST%OutFmt, 'dXdu', UseRow=xUse, UseCol=uUse) - if (allocated(Lin%dYdx)) call WrPartialMatrix(Lin%dYdx, Un, p_FAST%OutFmt, 'dYdx', UseRow=yUse, UseCol=xUse) - if (allocated(Lin%dYdu)) call WrPartialMatrix(Lin%dYdu, Un, p_FAST%OutFmt, 'dYdu', UseRow=yUse, UseCol=uUse) + if (allocated(Lin%dXdx)) call WrPartialMatrix(Lin%dXdx, Un, LinFmt, 'dXdx', UseRow=xUse, UseCol=xUse) + if (allocated(Lin%dXdu)) call WrPartialMatrix(Lin%dXdu, Un, LinFmt, 'dXdu', UseRow=xUse, UseCol=uUse) + if (allocated(Lin%dYdx)) call WrPartialMatrix(Lin%dYdx, Un, LinFmt, 'dYdx', UseRow=yUse, UseCol=xUse) + if (allocated(Lin%dYdu)) call WrPartialMatrix(Lin%dYdu, Un, LinFmt, 'dYdu', UseRow=yUse, UseCol=uUse) end if end if @@ -1494,10 +1502,10 @@ subroutine ModGlue_CalcWriteLinearMatrices(Vars, Lin, p_FAST, y_FAST, t_global, ! Write the linearized state matrices write (Un, '(/,A,/)') 'Linearized state matrices:' - if (allocated(Lin%dXdx)) call WrPartialMatrix(Lin%dXdx, Un, p_FAST%OutFmt, 'A', UseRow=xUse, UseCol=xUse) - if (allocated(Lin%dXdu)) call WrPartialMatrix(Lin%dXdu, Un, p_FAST%OutFmt, 'B', UseRow=xUse, UseCol=uUse) - if (allocated(Lin%dYdx)) call WrPartialMatrix(Lin%dYdx, Un, p_FAST%OutFmt, 'C', UseRow=yUse, UseCol=xUse) - if (allocated(Lin%dYdu)) call WrPartialMatrix(Lin%dYdu, Un, p_FAST%OutFmt, 'D', UseRow=yUse, UseCol=uUse) + if (allocated(Lin%dXdx)) call WrPartialMatrix(Lin%dXdx, Un, LinFmt, 'A', UseRow=xUse, UseCol=xUse) + if (allocated(Lin%dXdu)) call WrPartialMatrix(Lin%dXdu, Un, LinFmt, 'B', UseRow=xUse, UseCol=uUse) + if (allocated(Lin%dYdx)) call WrPartialMatrix(Lin%dYdx, Un, LinFmt, 'C', UseRow=yUse, UseCol=xUse) + if (allocated(Lin%dYdu)) call WrPartialMatrix(Lin%dYdu, Un, LinFmt, 'D', UseRow=yUse, UseCol=uUse) ! Close file close (Un) @@ -1553,11 +1561,11 @@ subroutine WrLinFile_txt_Table(VarAry, FlagFilter, p_FAST, Un, RowCol, op, IsDer end if ! tab stop after operating point - TS = 14 + 3*p_FAST%FmtWidth + 7 + TS = 14 + 3*LinFmtWidth + 7 ! Construct write formats - Fmt = '(3x,I8,3x,'//trim(p_FAST%OutFmt)//',T'//trim(Num2LStr(TS))//',L8,8x,I8,9x,A)' - FmtRot = '(3x,I8,3x,'//trim(p_FAST%OutFmt)//',2(", ",'//trim(p_FAST%OutFmt)//'),T'//trim(Num2LStr(TS))//',L8,8x,I8,9x,A)' + Fmt = '(3x,I8,3x,'//LinFmt//',T'//trim(Num2LStr(TS))//',L8,8x,I8,9x,A)' + FmtRot = '(3x,I8,3x,'//LinFmt//',2(", ",'//LinFmt//'),T'//trim(Num2LStr(TS))//',L8,8x,I8,9x,A)' FmtStr = '(3x,A10,1x,A,T'//trim(Num2LStr(TS))//',A15,1x,A16,1x,A)' ! Write header From 51ec9f0dbeb9e934de05a0977779582c95d90553 Mon Sep 17 00:00:00 2001 From: Mayank Chetan <4620557+mayankchetan@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:54:29 -0600 Subject: [PATCH 3/3] Revert lic related, stale edit from my fork Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 3b43f8bbe7..8dada3edaf 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 NREL + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.