From input file to verifiable result
Current MKE-F is a GNU Octave program with a functional numerical core. Model data are created once, solvers return new result structures, and plotting and printing are separate from computation.
Responsibilities
| Layer | Task | Main code |
|---|---|---|
| Input | Read sections to EOF, validate records and create elements. | FEMesh.m, createStructuralElement.m |
| Assembly | Accumulate element contributions into sparse global K and M. | assembleGlobalMatrices.m |
| Model | Snapshot of matrices, DOF mapping, supports, loads and element data. | createAnalysisModel.m |
| Numerical core | Reduce DOFs, solve and create a new result structure. | solveStatic.m, solveModal.m, solveTransient.m |
| Results | Reactions, equilibrium, local forces and spectrum. | calculateStaticEquilibrium.m, recoverElementResults.m, computeSingleSidedSpectrum.m |
| Compatibility and presentation | Familiar commands RunStatic, RunModal, RunTransient, optional printing and plotting. | StructFEProblem.m, plotTransientResult.m |
The root function setup explicitly adds directories src/model,
src/analysis, src/results and scripts to the Octave path.
Supplied models are in examples/cases, ready-to-use
postprocessor data are in examples/results, and new results are written
to the ignored directory output.
addpath(pwd);
setup;
problem = StructFEProblem(fullfile( ...
"examples", "cases", "CaseBeam.txt"));
model = problem.GetAnalysisModel();
staticResult = solveStatic(model);
modalResult = solveModal(model);
Start the container interface from the project root with docker compose up --build or docker-compose up --build. In the preprocessor create a model or open a TXT file containing section analysis and click Run analysis. The backend always calls the fixed RunSelected(); the browser never supplies script names, paths or Octave expressions.
Calling a solver does not change model, problem.K or problem.M. Loads are rebuilt for every run, so repeated analysis and changes in analysis order should not change the result.
Elements and sparse assembly
An element is a plain value structure, not a mutable subclass instance. createStructuralElement creates a common contract for types 112 and 113: type, nodeNumbers, properties, a unified vector dofs, matrices and stored length and transformation. The same DOF map is used for assembly and force recovery.
assembleGlobalMatrices first builds row–column–value triplets, then a single call to sparse creates the global matrices. Octave sums contributions at repeated addresses. Memory depends on the number of element coefficients, not the square of the total DOF count.
Element mathematics is concentrated in one structure constructor; solvers do not know individual element formulas, and result recovery uses the stored matrices and transformation.
Validation and headless operation
FEMesh checks file opening, section order, field count, finite values, node numbers, element properties, load types and the prohibition on mixed meshes. onCleanup closes the file even on error. Parser messages contain the filename and line; the complete contract is in chapter 10.
By default, verbose=false and plotting=false. Task creation and all three analyses therefore work locally in a terminal without a graphical display. Mesh and history plotting are separate actions; axis equal does not distort mesh geometry.
octave --no-gui --quiet --eval "addpath(pwd); setup; run_octave_tests;"
Verification sequence
run_octave_smoke_testsreads supplied cases, checks sparse assembly and runs available analysis types.run_verification_testschecks element and global invariants, independent formulas, reactions, loads and call order.- Specialized files check element matrices, assembly, the Mario Paz modal example, Newmark integration, forces and input.
- Reference laboratories add educational, executable checks of actual production code.
The matrices, frequencies and modes of Illustrative Example 11.1 from Mario Paz and William Leigh have been reconstructed and are checked by a dedicated test. Old output snapshots and discrepancies with ANSYS are still not treated as oracles: references are the published example, analytical solutions and explicit invariants.
The 2017 versions and the current program
The author’s articles document project origins but describe the MATLAB architecture of their time. Their class names, breakpoints, matrix mutation order and numerical discrepancies must not be copied into current instructions.
| Historical material | What it records | Current equivalent |
|---|---|---|
| “MKE-F — Newmark method”, v0.4 | Adoption of Newmark integration and the old MATLAB transient-analysis call. | solveTransient, initial conditions, full histories and the verifiable β=1/4, γ=1/2 scheme. |
| “Mass matrix and stiffness matrix”, v0.6.0 | Types 112/113, consistent mass and the former hierarchy FiniteElementStructural/Beam2DElement/Truss2DElement. | createStructuralElement returns a structure; unified triplet assembly replaces mutable classes and methods Assembler. |
| “Frame analysis in MKE-F”, v0.6.0 era | Origin of the case ANSYSBeamStatic01.txt and the historical comparison with Beam188. | The file remains a regression input, but the old article’s 5% discrepancy is not a required result. |
The “v0.6.0 era” label is chronological: the following day the author explicitly identified the current version as v0.6.0. The frame article itself does not print a version number.
Completed improvement plan map
The following preserves every completed item of the former ToDo.md. Each item names current code and a check; where an intermediate solution was later replaced, its present equivalent is listed.
1. GNU Octave compatibility and local verification
- The minimum GNU Octave version 8.4 and local verification on 11.3 are documented in the local workflow chapter; the verification entry point is
run_octave_tests.m. - The headless command is implemented in
run_octave_smoke_tests.mand run locally by the developer. - All supplied cases assemble, and static, modal, pulse and harmonic analyses run in
run_octave_smoke_tests.m; matrix invariants are repeated intests/run_verification_tests.m. - The intermediate concrete fallback methods of the old abstract class were later replaced by structures in
createStructuralElement.m; the interface is checked bytests/test_element_matrices.m. - Testing arrays of homogeneous handle-class elements became irrelevant after migration to structures; their array is created by
FEMesh.mand checked by the smoke test. - Optional printing and plotting are implemented in
StructFEProblem.m; defaults are checked bytests/test_input_validation.m. - UTF-8 is specified in
.editorconfig; reading Russian files is exercised by all smoke tests. - Octave-supported operations and repeated solves are concentrated in
solveTransient.mandvalidateReducedSystem.m; these are checked bytests/test_newmark_transient.m. - The small local runner is
run_octave_smoke_tests.m; successful completion is the check itself. - The single-argument constructor is preserved in
StructFEProblem.m, and headless settings are checked intests/test_input_validation.m.
2. Self-contained verification suite
- The Octave-only checks are in
tests/run_verification_tests.mand included throughrun_octave_tests.m. - Dimensions, finiteness and symmetry of K/M are checked by
testMatrixInvariantsin the same file andtests/test_element_matrices.m. - Formulas FL/(EA) and PL³/(3EI) are checked by
testSingleAxialTrussandtestCantileverBeam. - Reactions, mass, single-step pulse and harmonic samples are checked by
tests/run_verification_tests.m. - All supplied files serve as no-crash regression checks in
run_octave_smoke_tests.m. - Explicit absolute and relative tolerances are implemented by helper functions
assertCloseandassertRelativeSmallin the tests. - The complete local suite runs through
run_octave_tests.m. - The Mario Paz example is checked against published matrices, frequencies and modes in
tests/test_mario_paz_modal.m; the ANSYS example remains historical context only.
3. Element matrices
- The symmetric coefficient
-22*Lof the frame consistent mass matrix is increateStructuralElement.m; symmetry is checked bytests/test_element_matrices.m. - Coefficients EA/L, 12EI/L³, 6EI/L² are written explicitly there and compared with an independent matrix in the same test.
- Zero length and nonpositive A, E, ρ, I are rejected in
createStructuralElement.m;testInvalidElementDatachecks the errors. - Horizontal, vertical and inclined orientations are checked by functions
testTrussOrientationsandtestBeamOrientations. - Symmetry, rank, rigid-body modes, rotational invariance and mass are checked in
tests/test_element_matrices.m.
4. Functional core
- The model separates data from results in
createAnalysisModel.m;testFunctionalAnalysisCorechecks immutability. - Pure entry points are
solveStatic.m,solveModal.m,solveTransient.m; the facade delegates to them inStructFEProblem.m. - K and M are not modified: this is explicitly checked by
testFunctionalAnalysisCore. - Fresh loads for each run are created by
buildStaticLoad.mandbuildTransientLoad.m; the same test compares repeated calls. - Two identical runs are compared in
testFunctionalAnalysisCore. - Independence from static, modal and dynamic call order is checked there as well.
- Named fields are populated by the three
solve*.m; the same test checks key fields. - Plotting is separated into
plotTransientResult.m, while printing stays in the facade; headless operation is checked by the smoke test andtests/test_input_validation.m.
5. Free-DOF reduction
fixedDOFsandfreeDOFsconstructspartitionDOFs.m; the mapping is checked bytestFreeDOFReduction.- Reduced K and M are used by all three solvers; corresponding slices are checked in
tests/run_verification_tests.m. - Spurious zero modes are eliminated in
solveModal.m; positive frequencies are checked bytestFreeDOFReduction. - A load on a constrained DOF is retained in
solveStatic.m; its reaction is checked by the same test. - Global equilibrium is calculated by
calculateStaticEquilibrium.m; bar/cantilever tests check zero residuals. - Repeated, invalid and insufficient constraints are rejected by
partitionDOFs.mandvalidateReducedSystem.m; errors are checked bytestConstraintValidation.
6. Nodal load semantics
- Indexed DOF assembly is performed by
getNodalLoadComponents.mtogether with the load builders; multiple records are checked bytestNodalLoadSemantics. - The third frame component is treated as Mz, and rejected for a truss; the code and test are the same.
- Historical type 10 produces one rectangular step in
buildTransientLoad.m; the exact sample is checked bytestNodalLoadSemantics. - Explicit
bcforce_pulse/type 12 is read byFEMesh.m; input fileCaseExplicitPulseBeam.txtis checked in the load test. bcforce_step/type 13 is implemented by the same files; input fileCaseStepBeam.txtchecks a constant history.- Summation of multiple loads at the same and different nodes is checked by
testNodalLoadSemantics.
7. Newmark transient analysis
- Average acceleration with β=1/4, γ=1/2 is implemented in
solveTransient.m; parameters are checked bytests/test_newmark_transient.m. - The grid with first column t=0 is implemented there and checked in
testFreeVibrationAndInitialState. - Initial u, v and equilibrium-based acceleration are implemented there; the same test and invalid-input scenarios check them.
- Histories of size
stepCount+1are preallocated insolveTransient.m; the transient-analysis test checks their size. - The constant effective matrix is factorized once there; the full transient test suite checks solution consistency.
- FFT and single-sided normalization are performed by
computeSingleSidedSpectrum.m; the peak is checked bytestSingleSidedSpectrum. - Histories and spectra are returned independently of graphics; transient tests check the fields, and plotting is separated into
plotTransientResult.m. - Analytical SDOF response, energy and convergence are checked in
testFreeVibrationAndInitialState,testImpulseResponseAndConvergenceandtestBeamImpulseRefinement.
8. Result recovery
- The compatibility name
StressCalc.mdelegates to the new implementationrecoverElementResults.m; the interface is checked bytests/test_result_recovery.m. - Truss strain, stress and axial force are calculated by
recoverElementResults.m; straight and rotated members are checked there. - The same function returns local frame end forces; diagrams were initially deferred until distributed loads were available, and the cantilever is checked by
testCantileverEndForces. - Single-member and cantilever references are in
tests/test_result_recovery.m.
9. Simpler, faster assembly
- Structures and pure functions are implemented in
createStructuralElement.m; matrix and result-recovery tests check the interface. - The class value-semantics item was resolved by removing the mutable hierarchy; the absence of handle-class elements follows from the structures
FEMesh.allMeshElemsand is checked by the smoke test. - The unified field interface is used by
assembleGlobalMatrices.mandrecoverElementResults.m; both paths have dedicated tests. - A single
element.dofscreatescreateStructuralElement.m; mapping and summation are checked bytests/test_sparse_assembly.m. - Triplet sparse matrices are created by
assembleGlobalMatrices.m;testSuppliedCasesAreSparseandtestLargeTrussChaincheck the result. - Length and transformation are cached in the element structure; matrix and recovery tests use and verify these data.
- The full verification suite and smoke tests ensure baseline results are preserved.
10. Input, documentation and presentation
- The read-to-EOF loop is in
FEMesh.m; repeated sections and unknown markers are checked bytests/test_input_validation.m. fopen,onCleanupand line numbers are implemented there; the same test checks opening errors and invalid records.- Repeated supports and loads are appended in
FEMesh.m;CaseRepeatedSections.txtchecks the count and sum. - Node numbers, connectivity, property counts and plotted DOF selection are checked by
FEMesh.m/StructFEProblem.m; test input files andtestPlotSelectionAndDefaultscheck the errors. - Mixed types are rejected as
MKEF:UnsupportedMixedMesh;CaseMixedElements.txtchecks the error line. - Optional graphics and printing are in
StructFEProblem.m, andaxis equalinFEMesh.m; the input test checks default values. - Units, DOFs, loads, limitations, sources and commands are preserved in this reference, especially in chapter 10; laboratories and the full test suite provide executable confirmation.
Analysis diagnostics
| Symptom | Likely cause | What to check |
|---|---|---|
MKEF:SingularStiffness | A mechanism, disconnected node or insufficient supports. | Connectivity, element lengths, fixedDOFs; do not “fix” a mechanism by adding ones to K. |
MKEF:SingularMass or an invalid modal problem | Nonpositive or singular reduced mass. | ρ, A, I, free DOFs and connectivity. |
| Unexpected reaction or force sign | Global and local systems, or forces on the structure and on an element, have been confused. | element.transformation, the order of localEndForces and chapter 8. |
| Unexpected dynamic impulse | Type 10 was mistaken for a constant step. | Use type 12 for an explicit pulse and type 13 for a step; see chapter 4. |
| Error with filename and line number | A section format rule was violated. | Compare the record with chapter 10; retain the line number in any error report. |
Chapter source code
FEMesh.m— parser, validation and mesh data;createAnalysisModel.mandStructFEProblem.m— model boundary and compatibility facade;assembleGlobalMatrices.m— sparse assembly;run_octave_tests.mandtests/run_verification_tests.m— common verification entry points.
Project history
- Daniil Denisov, “MKE-F — Newmark method,” November 25, 2017, version 0.4.
- Daniil Denisov, “Mass matrix and stiffness matrix,” December 20, 2017, version 0.6.0.
- Daniil Denisov, “Frame analysis in MKE-F,” December 19, 2017, v0.6.0 era.