mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-29 23:52:49 +00:00
feat(materials): add material field trait system
New 140-line material field trait system: - required_material_fields(): define fields required by physics (Elasticity, Thermal) - material_field_type(): infer field NamedTuple type from material's supported physics - compose_field_types(): compose multiple NamedTuple types for multi-physics - Supports Elasticity (σ, 𝔻) and Thermal (q, k) physics - Type-stable field type inference - Already integrated in JuliaFEM.jl (line 431) Provides compositional field design for material-physics coupling.
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
"""
|
||||
Material field trait functions for compositional field design.
|
||||
"""
|
||||
|
||||
using Tensors
|
||||
using ..JuliaFEM: AbstractPhysics, Elasticity, Thermal
|
||||
|
||||
# ============================================================================
|
||||
# MATERIAL FIELD TRAITS
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
required_material_fields(physics::AbstractPhysics) -> Type{<:NamedTuple}
|
||||
|
||||
Returns NamedTuple type defining material fields required by this physics.
|
||||
"""
|
||||
function required_material_fields end
|
||||
|
||||
# ============================================================================
|
||||
# PHYSICS-SPECIFIC IMPLEMENTATIONS
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
required_material_fields(::Elasticity{Dim}) where Dim
|
||||
|
||||
Elasticity physics requires stress (σ) and tangent modulus (𝔻).
|
||||
"""
|
||||
function required_material_fields(::Elasticity{Dim}) where Dim
|
||||
if Dim == 3
|
||||
return NamedTuple{
|
||||
(:σ, :𝔻),
|
||||
Tuple{
|
||||
SymmetricTensor{2,3,Float64,6},
|
||||
SymmetricTensor{4,3,Float64,36}
|
||||
}
|
||||
}
|
||||
elseif Dim == 2
|
||||
return NamedTuple{
|
||||
(:σ, :𝔻),
|
||||
Tuple{
|
||||
SymmetricTensor{2,2,Float64,3},
|
||||
SymmetricTensor{4,2,Float64,9}
|
||||
}
|
||||
}
|
||||
else
|
||||
error("Elasticity{Dim} with Dim=$Dim not supported")
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
required_material_fields(::Thermal{Dim}) where Dim
|
||||
|
||||
Thermal physics requires heat flux (q) and thermal conductivity (k).
|
||||
"""
|
||||
function required_material_fields(::Thermal{Dim}) where Dim
|
||||
if Dim == 3
|
||||
return NamedTuple{
|
||||
(:q, :k),
|
||||
Tuple{
|
||||
Vec{3,Float64},
|
||||
SymmetricTensor{2,3,Float64,6}
|
||||
}
|
||||
}
|
||||
elseif Dim == 2
|
||||
return NamedTuple{
|
||||
(:q, :k),
|
||||
Tuple{
|
||||
Vec{2,Float64},
|
||||
SymmetricTensor{2,2,Float64,3}
|
||||
}
|
||||
}
|
||||
else
|
||||
error("Thermal{Dim} with Dim=$Dim not supported")
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# FIELD TYPE INFERENCE
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
material_field_type(material::AbstractMaterial) -> Type{<:NamedTuple}
|
||||
|
||||
Infer material field NamedTuple type from material's supported physics.
|
||||
"""
|
||||
function material_field_type(material::AbstractMaterial)
|
||||
physics_tuple = supported_physics(material)
|
||||
|
||||
if isempty(physics_tuple)
|
||||
# No physics - empty fields
|
||||
return NamedTuple{(),Tuple{}}
|
||||
elseif length(physics_tuple) == 1
|
||||
# Single physics - direct mapping
|
||||
return required_material_fields(physics_tuple[1])
|
||||
else
|
||||
# Multiple physics - compose fields
|
||||
field_types = map(p -> required_material_fields(p), physics_tuple)
|
||||
return compose_field_types(field_types...)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
compose_field_types(nt_types::Type{<:NamedTuple}...) -> Type{<:NamedTuple}
|
||||
|
||||
Compose multiple NamedTuple types into one.
|
||||
"""
|
||||
@generated function compose_field_types(nt_types::Type{<:NamedTuple}...)
|
||||
# Collect all field names and types
|
||||
all_names = Symbol[]
|
||||
all_types = Type[]
|
||||
|
||||
for nt_type in nt_types.parameters
|
||||
names = fieldnames(nt_type)
|
||||
types = [fieldtype(nt_type, name) for name in names]
|
||||
append!(all_names, names)
|
||||
append!(all_types, types)
|
||||
end
|
||||
|
||||
# Build composed NamedTuple type
|
||||
names_tuple = Tuple(all_names)
|
||||
types_tuple = Tuple(all_types)
|
||||
|
||||
return :(NamedTuple{$names_tuple, $types_tuple})
|
||||
end
|
||||
|
||||
"""
|
||||
create_zero_field(::Type{FieldType}) where {FieldType<:NamedTuple}
|
||||
|
||||
Create zero-initialized field NamedTuple.
|
||||
"""
|
||||
@generated function create_zero_field(::Type{FieldType}) where {FieldType<:NamedTuple}
|
||||
names = fieldnames(FieldType)
|
||||
types = [fieldtype(FieldType, name) for name in names]
|
||||
zero_values = [:(zero($T)) for T in types]
|
||||
|
||||
return :(NamedTuple{$names}(($(zero_values...),)))
|
||||
end
|
||||
Reference in New Issue
Block a user