- Mathematical derivation of F = I + ∇u for finite strain
- Zero-allocation implementation achieving 34 ns median
- LLVM IR analysis confirms 0 heap allocations
- 92 SIMD vector operations detected
- Small strain vs finite strain formulations
- Comparison with old deprecated eval_dbasis!() API
- 502 lines: Complete performance analysis with benchmarks
Document decision to store integration point indices instead of data in Element struct.
Key rationale: Elements should store relationships (indices), not data, for memory
efficiency and consistency with node connectivity pattern. Aligns with nodal assembly
approach and GPU-friendly architecture.
Architectural Decision Record documenting design of integration points
API for high-performance finite element assembly.
Decision: Compile-time function returning tuple of (weight, Vec{D})
matching eval_basis! zero-cost abstraction pattern.
Problem context:
- OLD API: Runtime dispatch with mutable struct containing Dict
- Performance penalty: ~50× slower due to type instability
- Allocations: New struct created every query
- Impact: Millions of calls during assembly
Solution properties:
- Compile-time generation (fully inlined)
- Vec{D} from Tensors.jl for FEM math
- Zero allocation (tuples, stack-only)
- Type-stable (all types known at compile time)
- GPU compatible (no heap allocations)
API signature:
get_gauss_points!(::Type{Topology}, ::Type{Gauss{order}})
→ NTuple{N, Tuple{Float64, Vec{D}}}
Alternatives rejected:
- Plain tuples (less convenient for FEM math)
- Store in element (overhead, less flexible)
- Global constants (not composable)
- Runtime dispatch (type-unstable, slow)
Status: Accepted, implemented in src/integration/ (193 lines)
- Delete docs/blog/ directory (files moved to docs/src/book/blog/)
- Delete docs/design/ directory (files moved to docs/src/book/design/)
- Cleanup after three-tier documentation reorganization
- Old locations no longer needed after migration to docs/src/ structure
- Relocate docs/contributor/ to docs/src/contributor/
- Add three GPU quickstart guides (renamed from UPPERCASE to snake_case):
- gpu_elasticity_quickstart.md
- gpu_nodal_assembly_quickstart.md
- quick_reference_gpu.md
- Part of three-tier docs reorganization following Documenter.jl standard
- All files now under docs/src/ for automatic rendering
- Relocate docs/blog/immutability_performance.md to docs/src/book/blog/
- Comprehensive guide on immutable material models with Tensors.jl
- Covers LinearElastic, NeoHookean, PerfectPlasticity implementations
- Includes full benchmarks: 5× speedup for linear, 21× for plasticity
- Zero allocation performance validated
- Part of three-tier docs reorganization under standard docs/src/ structure
- Relocate docs/book/README.md to docs/src/book/README.md
- Follows standard Julia documentation structure where all source files live under docs/src/
- File contains YAML header and book philosophy/structure overview
- Part of three-tier documentation reorganization (user/contributor/book)
- Converted header metadata to YAML frontmatter format
- Added categories and tags for documentation site compatibility
- Preserved all existing content (only header format changed)
- Status: IMPLEMENTED, Phase: Phase 1B
- Links to benchmark: element_immutability_benchmark.jl
New 139-line quick-reference article covering:
- Side-by-side code comparisons (mutable vs immutable)
- 130x speedup summary with key metrics
- Type stability explanation with timing breakdown
- Compiler optimization differences
- Real-world impact table (2.4s → 0.02s)
- Mental model shift (1990s C++ → 2025 modern compilers)
- Quick command to run benchmark
- Links to full article for details
Implements compatibility layer to allow old test code to run with new
immutable element design (though fields won't actually update).
src/elements/elements.jl:
- Replaced has_dfield/get_dfield to work with new fields API
- Fixed get_sfield/get_dfield to handle empty Tuple{} fields
- All dfield functions now map to element.fields (immutable NamedTuple)
src/topology/*.jl (seg2, tri3, quad4, tet4, hex8):
- Added nnodes() implementation for each topology type
- Returns corner node count (backwards compatibility)
- Example: nnodes(::Triangle) = 3, nnodes(::Hexahedron) = 8
- Note: Actual node count depends on basis degree in new architecture
Test Results:
- test_topology_standalone.jl: 36/36 tests passing ✓
- Full test suite: 43 errors (same as before)
- Error breakdown:
* 40+ tests: Problem types not defined (Elasticity, Heat, Mortar)
* 2 tests: Mesh readers not defined (aster_read_mesh)
* 1 test: Tries to mutate empty element (test_elasticity_1d)
Next Steps:
- Tests that create empty elements then mutate need rewriting
- Pattern: Element(Seg2, (1,2)) + update!() → not compatible
- New pattern: Element(..., fields=(geometry=X, displacement=u))
- See docs/design/IMMUTABILITY.md for migration guide
Created comprehensive documentation and benchmark demonstrating why immutable
elements with type-stable fields are 40-130x faster than mutable Dict-based
elements.
benchmarks/element_immutability_benchmark.jl:
- Compares mutable (Dict) vs immutable (NamedTuple) implementations
- Measures field access, updates, assembly loops, large-scale meshes
- Results: 40x faster field access, 130x faster assembly, zero allocations
docs/design/IMMUTABILITY.md:
- Explains counterintuitive API change: element = update(element, ...)
- Benchmarks show 40-130x speedup despite 'copying' elements
- Key insight: Type stability >> mutation, compiler optimizes away copies
- Migration guide: old mutable API → new immutable API
- GPU/HPC rationale: Only bits types work on GPU (no pointers)
Key Results:
- Field access: 1ns vs 45ns (40x faster)
- Assembly: 9ns vs 1124ns per element (130x faster)
- Large mesh: 0.01ms vs 1.2ms for 1000 elements (120x faster)
- Memory: 0 allocations vs 70,000 allocations
- GPU: Compatible (bits types) vs Incompatible (pointers)
This documents a fundamental architectural decision for JuliaFEM 1.0.
Design for handling both nodal and element fields in nodal assembly:
Architecture:
- Nodes have geometry (immutable)
- Elements have connectivity + fields (immutable struct)
- Nodal fields: displacement, temperature, contact pressure
- Element fields: integration point data (σ, ε_plastic, α, C)
Update pattern:
- Create new field containers (NamedTuples)
- Create new elements with updated fields
- Shallow copy element vector, replace elements
- All immutable (GPU-compatible, thread-safe)
GPU kernel:
- Loops over nodes (nodal assembly)
- Accesses nodal_fields for global quantities
- Accesses element.fields for integration point data
- Gathers from connected elements (node_to_elements)
- No atomic operations (each node owns DOFs)
Material state update:
- Process elements in parallel (Threads.@threads)
- Extract nodal displacements from solution
- Compute strains at integration points
- Run material model (plasticity, damage, etc.)
- Create new elements with updated state
- Return new problem with updated fields
Newton iteration:
- Residual uses element.fields.C (current tangent)
- GMRES with matrix-free matvec (nodal assembly)
- Material update after each iteration
- All data structures immutable throughout
Benchmarks show creating new containers ~1000× faster than deepcopy
Explains why JuliaFEM uses nodal assembly instead of element assembly:
Five major advantages:
1. No atomic operations on GPU (each node writes to own DOFs)
2. Contact mechanics is natural (forces at nodes, not elements)
3. Clean domain decomposition (explicit node ownership for MPI)
4. Better cache locality (sequential node processing)
5. Adaptive refinement easier (local node operations)
Key data structure:
- NodeSet contains nodes + elements + node_to_elements connectivity
- Inverse connectivity enables gathering from connected elements
- Fields accessed via node_set.fields (type-stable)
Algorithm:
- Loop over nodes (not elements)
- Each node gathers contributions from connected elements
- Direct write to owned DOFs (no race conditions)
- Perfect for matrix-free Krylov methods
Validated with demo:
- CPU/GPU results match exactly (0.0 relative error)
- Average 3.24 elements per node (efficient gathering)
- Natural integration with contact mechanics
Compares to traditional element assembly:
- Element: scatter to nodes (atomic ops, cache misses)
- Nodal: gather from elements (no atomics, better cache)
Complete algorithm for GPU-resident FEM solver with nodal assembly:
- Data partitioning by node ownership (domain decomposition)
- GPU-resident data structures (nodes, elements, connectivity, state)
- Three GPU kernels: residual, matvec, state update
- MPI communication patterns for interface nodes
- Full Newton-GMRES loop on GPU (data stays resident)
Architecture:
- Each GPU owns subset of nodes (exclusive ownership)
- Ghost elements copied for gathering during assembly
- node_to_elements connectivity enables nodal assembly
- No atomic operations (each GPU writes to owned DOFs only)
Key features:
- Data moves to GPU once at start, back once at end
- GMRES iterations entirely on GPU (Arnoldi steps)
- Material state updates on GPU (integration points)
- MPI exchanges only for interface DOFs between iterations
- O(N) memory per GPU (matrix-free)
Handles nonlinearity:
- Element state contains σ, ε_plastic, α, C (tangent)
- Residual kernel uses current stress/tangent
- State update kernel after convergence
- Natural for contact mechanics (nodal forces)
Status: Design document for future GPU implementation
Explains the correct pattern for matrix-vector products in Krylov methods:
- Fields accessed through element_set (not passed separately)
- GPU kernel computes y=K*x (not K itself)
- O(N) memory (vs O(N²) for stored matrix)
- Type-stable field access (compile-time types)
Key insights:
- GMRES needs matvec operation, not the matrix
- ElementSet contains elements + fields together
- Zero allocations with immutable connectivity/fields
- Natural pattern for contact mechanics (nodal updates)
- Material state separate from field parameters
Compares old vs new approach:
- Old: Dict{String,Any} in element (type-unstable)
- New: NamedTuple in ElementSet (type-stable)
- Old: O(N²) matrix storage
- New: O(N) matrix-free operator
Validated with gpu_elementset_matvec_demo.jl:
- GPU/CPU results match exactly
- Fields accessed naturally through element_set
- Returns y vector (what Krylov methods need)
Analyzes field storage patterns and recommends ElementSet approach:
- Element has NO field type parameter (simpler type)
- ElementSet groups elements + shared fields
- Fields can be NamedTuple, struct, any type-stable container
- Embraces immutability (GPU-compatible, thread-safe)
- Separates mutable state from immutable parameters
Design rationale:
- Benchmarks show NamedTuple gives 9-92× speedup vs Dict
- Immutability enables GPU execution without copying
- Creating new containers ~1000× faster than deepcopy
- Matches physical reality (material properties per set)
Compares three options:
1. Fields as type parameter (type proliferation)
2. ElementSet pattern (RECOMMENDED)
3. Hybrid approach (too complex)
Addresses common concerns:
- Time-dependent fields (use interpolation)
- Material state (separate mutable arrays)
- Custom field types (any type-stable container works)
Status: Ready for implementation
Remove duplicate "JuliaFEM Documentation" header (line 11) and add blank lines
for consistent list formatting in three-manual organization document.
Changes:
- Line 11: Removed duplicate H1 title (already in frontmatter)
- Lines 22, 41, 61, 110: Added blank lines before list items for markdown clarity
- Maintains three-audience structure: Users, Contributors, Researchers
- Preserves content organization and cross-reference section
This is a formatting-only change to improve readability. No content modified.
Create 299-line focused design rationale explaining why type stability is essential
for CPU/GPU/MPI performance, without mandating specific storage patterns.
Executive summary (lines 16-26):
- v0.5.1 Dict{String,Any}: 9-92× performance degradation
- Type-unstable code CANNOT run on GPUs
- Significant MPI communication overhead
- Document does NOT prescribe storage location
- Demonstrates why type stability at access points is essential
- Key: Storage pattern matters less than type inference
Problem analysis (lines 28-67):
- Type instability definition: Runtime dispatch when type unknown at compile time
- Why it matters: 10-100× slower CPU, GPU compilation fails, MPI serialization
- Measured impact table: 9-92× speedup, 0 allocations with type stability
- Critical: Zero allocations required for GPU kernels
Design requirements (lines 69-136):
1. Type stability at access points (compiler must infer types)
- Fields could be element-local, global arrays, or arguments
- Access pattern must be type-stable regardless
2. Zero allocations in hot paths (GPU/MPI requirement)
- Assembly loop must allocate nothing
3. Contiguous memory layout (GPU/MPI optimization)
- CUDA transfers contiguous arrays directly
4. Immutable where possible (safe parallelism)
- Thread-safe reads without locks
Demonstrated solutions (lines 138-201) - EXAMPLES, not mandates:
1. NamedTuple container: Simple, type-stable, immutable
2. Struct with typed fields: Explicit, self-documenting
3. Passed as arguments: Maximum type stability, explicit dependencies
- All three achieve type stability
- Choice depends on use case, not performance
GPU and MPI rationale (lines 203-237):
- GPU execution: CUDA requires all code type-stable
- Mock demonstration in benchmarks/gpu_mpi_mock.jl
- MPI communication: Typed arrays use fast memcpy vs slow serialization
- Type stability enables identical code for CPU/GPU
Recommendations (lines 239-256):
- Use type-stable access patterns (REQUIRED)
- Prefer immutable data structures (threading/GPU)
- Pre-allocate caches (zero allocations)
- Use contiguous arrays (GPU/MPI transfer)
- Profile with @btime (verify zero allocations)
- Does NOT mandate: Storage location, container type, dynamic vs static
Validation (lines 258-275):
- benchmarks/field_storage_comparison.jl: 9-92× CPU speedup
- benchmarks/gpu_mpi_mock.jl: GPU/MPI patterns
- benchmarks/VALIDATION_RESULTS.md: Summary table
Conclusion (lines 277-299):
- Type stability is fundamental requirement, not implementation detail
- Enables: High CPU performance, GPU execution, efficient MPI, safe threading
- v1.0 must ensure type stability at access points
- Storage pattern is secondary concern (memory, cache, API)
- Next steps: Review, benchmark, choose pattern, implement, validate CUDA
Key difference from v1: Shorter (299 vs 1114 lines), focused on WHY not HOW,
explicitly states storage pattern is flexible, emphasizes GPU/MPI requirements.
Platform: Julia 1.12.1, November 9, 2025
Series: The JuliaFEM Book, Chapter 5
Status: Design rationale with validated measurements
Create 415-line blog post combining technical demonstration with philosophical
vision for JuliaFEM v1.0 nodal assembly architecture.
Content structure:
- Lines 1-32: Why Krylov+nodal is brilliant for contact mechanics
* Contact is inherently nodal (constraints at nodes, not elements)
* Krylov only needs matvec (never forms global matrix)
* Nodal assembly provides natural row-by-row interface
* O(N) memory vs O(N²) for traditional element assembly
- Lines 34-73: Controversial hypothesis about nodal material modeling
* Claims material state should be at nodes, not integration points
* Argues integration points constrain physics to numerical method
* Variational consistency, physical meaning, scalability arguments
* "I will show them they're wrong" - experimental vision
- Lines 75-95: GMRES advantage for unsymmetric systems
* Material nonlinearity, contact, large deformation all unsymmetric
* GMRES solves positive definite unsymmetric systems
* O(N·iter) time, O(N) memory vs O(N³)/O(N²) for direct solvers
- Lines 97-415: Working GMRES demonstration on 10×10 unsymmetric system
* Problem setup: Positive definite but unsymmetric matrix (lines 105-145)
* Nodal assembly pattern: get_row() interface (lines 147-193)
* Simplified GMRES implementation (lines 195-282)
* Execution and verification (lines 284-318)
* Results: Converged in 10 iterations, 6.28×10⁻¹⁶ relative error
* Key insights section explaining significance (lines 320-365)
* Development roadmap: Immediate → Near-term → Long-term → Vision (lines 367-401)
* Conclusion: Philosophical statement about nodal correctness (lines 403-415)
Technical validation:
- Matrix: 10×10, eigenvalues [9.94, 38.06], condition number 3.83
- Nodal matvec: 1.59×10⁻¹⁴ error vs direct computation
- GMRES: 10 iterations to convergence
- Solution accuracy: 1.23×10⁻¹⁴ absolute error, 6.28×10⁻¹⁶ relative
Dependencies: LinearAlgebra, Random, Printf
Format: Literate.jl (# # for section headers, # for narrative)
Target: Blog post for JuliaFEM v1.0 development documentation
Tone: Opinionated, controversial, technically rigorous
Major documentation update (380 additions, 167 deletions):
- Explained topology is pure geometry (NO hardcoded node counts)
- Clarified basis determines BOTH polynomial degree AND node count
- Distinguished node count (connectivity) vs DOF count (unknowns)
- Added examples: Nedelec (edge DOFs), Raviart-Thomas (face DOFs)
- Documented Lagrange{Topology, P} parametric architecture
- Showed why Tri3/Quad4/Tet10 names are anti-pattern
- Updated all code examples to use new architecture
- Explained Serendipity vs full Lagrange tensor products
- Added performance implications and trade-offs
- Showed how one Triangle topology works for P1/P2/P3/Nedelec/etc
- Removed redundant H1 heading (already in YAML frontmatter)
- Moved "Coding Standards" above "Architecture" in What's Here section
- Updated "Before Contributing" list to prioritize standards (now item 2)
- Marked coding standards as REQUIRED for all contributions
- Changed reference from "Code Style" to "Coding Standards" (file renamed)
- Added blank line after "We assume you:" for better formatting
New 500-line standards document covering:
- Core principles (readability, type stability, zero allocations, explicit code)
- Variable naming: NO Greek letters in code (critical rule - use u,v,w not ξ,η,ζ)
- Type naming: PascalCase for types, snake_case for functions, Basis suffix pattern
- Performance guidelines: type stability, zero allocations, tuple returns
- Documentation style: docstrings with examples, theory, performance notes
- Testing standards: test organization, floating point comparisons
- Anti-patterns: Dict without types, abstract types in structs, globals, type piracy
- Git commit style: Conventional Commits format with examples
- Editor configuration: .editorconfig and JuliaFormatter.toml settings
- Summary checklist for pre-submission verification
Rationale for no Greek letters: keyboard accessibility, editor compatibility,
copy-paste issues, search/replace problems, terminal rendering, git diffs,
internationalization, and accessibility concerns.
**Purpose:** Comprehensive justification for all technical decisions prioritizing
performance over convenience.
**Key Principles:**
- Efficiency > Educativeness (when forced to choose)
- Type stability over everything (100× performance difference)
- No free lunch - Julia doesn't make miracles
- HPC requires discipline and trade-offs
**Core Decisions Justified:**
1. **No Dynamic Field System**
- field["foo"] = x is 100× slower (Dict{String,Any})
- Type-stable structs only
- Sacrifice: Runtime flexibility
- Gain: Performance
2. **Immutable Data Structures**
- struct over mutable struct
- Sacrifice: Convenient mutation
- Gain: 2-10× speedup, thread-safety, stack allocation
3. **NTuple Over Vector**
- Compile-time size → SIMD optimization
- Sacrifice: Dynamic sizing
- Gain: Zero allocations, type stability
4. **Monolithic Over Multi-Package**
- Learned from 2015-2019 mistake
- Sacrifice: Small dependencies
- Gain: It actually works
5. **Manual Derivatives (hot paths)**
- 30× faster than AD for Tet10
- Sacrifice: More code
- Gain: Assembly loops stay fast
6. **Matrix-Free Methods**
- Design for 1M+ DOF from day 1
- Cannot retrofit later
7. **Explicit Over Implicit**
- No magic, show the steps
- Debuggable and teachable
**Hierarchy of Values:**
1. Correctness
2. Performance
3. Maintainability
4. Educativeness
5. Convenience
**What We're Giving Up:**
- Runtime flexibility (no element["custom_field"])
- Dynamic problem definition (no runtime topology changes)
- Duck typing convenience
- Small dependencies
- Beginner-friendly magic
**What We're Getting:**
- 10× single-thread speedup target
- 1M DOF contact problems
- Thread/GPU/distributed scalability
- Real HPC capability
**The Hard Truth:**
From Issue #266: "Do like Python, be slow like Python. Know what you do
before compiling, and be fast like C. There's no free lunch."
**Success Metrics:**
- ✅ Zero allocations in assembly
- ✅ Type-stable hot paths
- 🎯 10× faster than v0.5.1
- 🎯 1M DOF in < 1 hour
- 🎯 100+ thread scaling
**Use Cases:**
- "Why can't I use Dict?" → Point here
- "Why immutable?" → Point here
- "Why manual derivatives?" → Point here
- Any "why not convenience?" → Point here
**Status:** Living document, updated as we learn
See: Issue #266, TECHNICAL_VISION.md, benchmark results
**Three Manuals for Three Audiences:**
1. **User Manual** (docs/user/) - "Just Get It Done"
- For end users, engineers, students
- Simple, practical, step-by-step
- Quick start, tutorials, examples, troubleshooting
- Philosophy: Show me how to solve my problem
2. **Contributor Manual** (docs/contributor/) - "Show Me the Code"
- For developers, contributors, advanced users
- Technical, detailed, design rationale
- Testing, architecture, performance, CI/CD
- Philosophy: Explain HOW and WHY
3. **The JuliaFEM Book** (docs/book/) - "Let Me Show You How I Think"
- For researchers, theory nerds, and Jukka
- Comprehensive, educational, opinionated, personal
- Math foundations, design philosophy, history, research
- Philosophy: Mix theory, code, and personal experience
**Reorganization:**
- Moved: TESTING_PHILOSOPHY.md → contributor/testing_philosophy.md
- Moved: STATUS.md → contributor/status.md
- Moved: TEST_FIXES_NEEDED.md → contributor/test_fixes_needed.md
- Moved: lagrange_basis_functions.md → book/lagrange_basis_functions.md
- Moved: benchmarks/ → book/benchmarks/
- Created: docs/README.md (main index explaining structure)
- Created: README.md in each section explaining audience and contents
- Updated: All references in scripts and source files
**Naming:** All docs now lowercase (testing_philosophy not TESTING_PHILOSOPHY)
**Benefits:**
- Clear separation of concerns
- Users don't get overwhelmed with implementation details
- Contributors get technical depth
- Book preserves deep theory and personal insights
- Each manual optimized for its audience
**Next:** Populate each section with appropriate content
- Moved docs/theory/lagrange_basis_functions.md → src/lagrange_basis_functions.md
- Updated all references in scripts and source files
- Using lowercase for consistency (no uppercase in filenames)
- Documentation now under src/ for automated doc generation
Rationale: Documentation should be close to implementation and follow
consistent naming conventions (lowercase).
RESEARCH QUESTION: Should JuliaFEM use hand-calculated derivatives or AD?
Created comprehensive benchmark comparing:
- Manual: Hand-calculated derivatives (traditional FEM)
- AD: Tensors.jl gradient() (automatic differentiation)
RESULTS (AMD Ryzen 9, Julia 1.12.1):
- Manual: 8.7 ns, 0 allocations
- AD: 268.1 ns, 0 allocations
- AD is 30× SLOWER than manual
KEY FINDINGS:
✅ Both achieve zero allocations (Tensors.jl is well-optimized)
❌ AD has 30× compute overhead from dual number arithmetic
⚠️ In assembly loops: millions of calls = 10+ seconds extra per solve
RECOMMENDATION:
- Keep manual derivatives for common elements (Tet10, Hex8, Quad4, etc.)
- Use AD for prototyping and rare elements
- Unit test manual vs AD to catch errors
- Future: Generate derivatives symbolically (Symbolics.jl)
WHY NOT AD EVERYWHERE?
Assembly is hottest path in FEM. 30× overhead = unacceptable for
production code. Users will notice the performance difference.
WHY NOT ABANDON AD?
- Excellent for prototyping
- Required for exotic bases (NURBS)
- Perfect for unit testing manual derivatives
- Zero allocations impressive
Files:
- benchmarks/tet10_derivatives_benchmark.jl (runnable benchmark)
- docs/benchmarks/shape_function_derivatives_ad_vs_manual.md (analysis)
Dependencies added: BenchmarkTools
This answers the research question definitively with data.
New testing strategy: Educational tests using Literate.jl
Core principles:
- Tests are primary teaching material (not just validation)
- Literate.jl generates docs from test files (always synchronized)
- Structured progression: fundamentals → linear → nonlinear → advanced
- Fast tests (< 5 min unit, < 30 min full suite)
- Target: 99% code coverage
Test hierarchy:
- tutorials/ - Literate.jl files (test + documentation)
- unit/ - Fast isolated function tests
- verification/ - Known analytical solutions
8-week implementation roadmap:
Week 1: Infrastructure (Literate.jl setup)
Week 2-3: Core tutorials (10-15 fundamental topics)
Week 4-5: Advanced tutorials (contact, mortar)
Week 6: Unit tests (fill coverage gaps → 99%)
Week 7: Verification tests (validate correctness)
Week 8: Polish and publish documentation
Philosophy: 'Tests are not a chore - they teach users how to use JuliaFEM.'
Ready to start Phase 1 implementation.
Document the 49 failing tests with clear categorization:
- 14 tests need HDF5 (aster_read_mesh)
- 30 tests have API signature mismatches
- 2 tests already fixed (Analysis export, Statistics)
Includes 4-phase action plan with time estimates.
Good news: Core architecture is sound (package loads, 5 tests pass).
Failures are mechanical API compatibility issues from Julia evolution
(0.6 → 1.12 over 6 years), not fundamental problems.
- Add Tensors and Calculus to Project.toml dependencies
- Add basis includes to src/JuliaFEM.jl (Phase 1 integration)
- Fix FEMBasis. namespace references → use JuliaFEM namespace
- Update create_basis.jl: AbstractBasis (not FEMBasis.AbstractBasis)
Status: Basis files load, but conflict with FEMBase expectations
Next: Need to consolidate FEMBase or work around AbstractElement type constraints
This is expected during consolidation - we're bridging two systems.
It looks document generation proceduce has slightly changed.
docs/Project.toml is defining dependencies for document generation and
they are not explicitly given in `travis.yml`.
Let's use Literate.jl to automatically generate usage examples.
* Automatically generate documentation from other packages (first try to include each package's docs/src/index.md, but if that fails, then use README.md to introduce the package).
* Add example how to calculate local element matrices.
* Add example how to perform 2d contact analysis.