test: add 3d euler beam red fortran tests
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
- Phase directory: `phases/uel-3d-euler-beam`
|
- Phase directory: `phases/uel-3d-euler-beam`
|
||||||
- Current planned entry point: `python scripts/execute.py uel-3d-euler-beam`
|
- Current planned entry point: `python scripts/execute.py uel-3d-euler-beam`
|
||||||
- First pending step: `step0` requirements
|
- First pending step: `step7` Fortran implementation
|
||||||
|
|
||||||
## Planned Steps
|
## Planned Steps
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
4. Numerical review: `docs/numerical-reviews/uel-3d-euler-beam.md`
|
4. Numerical review: `docs/numerical-reviews/uel-3d-euler-beam.md`
|
||||||
5. Interface contract: `docs/io-definitions/uel-3d-euler-beam.md`
|
5. Interface contract: `docs/io-definitions/uel-3d-euler-beam.md`
|
||||||
6. Test/reference model plan: `docs/reference-models/uel-3d-euler-beam.md`
|
6. Test/reference model plan: `docs/reference-models/uel-3d-euler-beam.md`
|
||||||
7. RED no-Abaqus Fortran tests and manifest
|
7. RED no-Abaqus Fortran tests and manifest - completed
|
||||||
8. GREEN Fortran implementation
|
8. GREEN Fortran implementation - next
|
||||||
9. Validation, physics sanity, and readiness audit
|
9. Validation, physics sanity, and readiness audit
|
||||||
|
|
||||||
## Success Criteria
|
## Success Criteria
|
||||||
|
|||||||
+21
-6
@@ -5,8 +5,8 @@
|
|||||||
- Active objective: 3D Euler-Bernoulli beam Abaqus/Standard `UEL`
|
- Active objective: 3D Euler-Bernoulli beam Abaqus/Standard `UEL`
|
||||||
- Active phase: `phases/uel-3d-euler-beam`
|
- Active phase: `phases/uel-3d-euler-beam`
|
||||||
- Active owner: unassigned
|
- Active owner: unassigned
|
||||||
- Current status: completed `phases/uel-3d-euler-beam/step5.md` test/reference model planning step
|
- Current status: completed `phases/uel-3d-euler-beam/step6.md` RED no-Abaqus test creation step
|
||||||
- Next action: execute `phases/uel-3d-euler-beam/step6.md` RED no-Abaqus test creation step
|
- Next action: execute `phases/uel-3d-euler-beam/step7.md` Fortran implementation step
|
||||||
|
|
||||||
## Completed
|
## Completed
|
||||||
|
|
||||||
@@ -31,6 +31,15 @@
|
|||||||
- Completed step 5 test/reference model planning for `uel-3d-euler-beam`.
|
- Completed step 5 test/reference model planning for `uel-3d-euler-beam`.
|
||||||
- Created `docs/reference-models/uel-3d-euler-beam.md`.
|
- Created `docs/reference-models/uel-3d-euler-beam.md`.
|
||||||
- Updated `phases/uel-3d-euler-beam/index.json` step 5 to `completed`.
|
- Updated `phases/uel-3d-euler-beam/index.json` step 5 to `completed`.
|
||||||
|
- Completed step 6 RED no-Abaqus test creation for `uel-3d-euler-beam`.
|
||||||
|
- Created `tests/fortran/manifest.json`.
|
||||||
|
- Created `tests/fortran/uel_3d_euler_beam/test_support.f90`.
|
||||||
|
- Created `tests/fortran/uel_3d_euler_beam/test_kernel_stiffness.f90`.
|
||||||
|
- Created `tests/fortran/uel_3d_euler_beam/test_kernel_transform_modes.f90`.
|
||||||
|
- Created `tests/fortran/uel_3d_euler_beam/test_abi_static.f90`.
|
||||||
|
- Created `tests/fortran/uel_3d_euler_beam/test_invalid_inputs.f90`.
|
||||||
|
- Created `docs/build-test-reports/uel-3d-euler-beam-red.md`.
|
||||||
|
- Updated `phases/uel-3d-euler-beam/index.json` step 6 to `completed`.
|
||||||
|
|
||||||
## In Progress
|
## In Progress
|
||||||
|
|
||||||
@@ -42,22 +51,28 @@
|
|||||||
|
|
||||||
## Last Verification
|
## Last Verification
|
||||||
|
|
||||||
Latest verification after completing step 5 test/reference model planning:
|
Latest verification after completing step 6 RED no-Abaqus test creation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
python -m json.tool tests/fortran/manifest.json
|
||||||
python -m unittest discover -s scripts -p "test_*.py"
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
python scripts/validate_reference_artifacts.py
|
python scripts/validate_reference_artifacts.py
|
||||||
|
python scripts/validate_fortran.py
|
||||||
python scripts/validate_workspace.py
|
python scripts/validate_workspace.py
|
||||||
|
$env:HARNESS_FORTRAN_VALIDATION='detect'; python scripts/validate_workspace.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Result: all passed.
|
Result: RED evidence recorded.
|
||||||
|
- `python -m json.tool tests/fortran/manifest.json`: passed.
|
||||||
- `python -m unittest discover -s scripts -p "test_*.py"`: 56 tests passed.
|
- `python -m unittest discover -s scripts -p "test_*.py"`: 56 tests passed.
|
||||||
- `python scripts/validate_reference_artifacts.py`: reference artifact metadata validation succeeded.
|
- `python scripts/validate_reference_artifacts.py`: reference artifact metadata validation succeeded.
|
||||||
- `python scripts/validate_workspace.py`: succeeded; `validate_fortran.py` reported no Fortran validation commands configured because `tests/fortran/manifest.json` does not exist yet.
|
- `python scripts/validate_fortran.py`: default process failed before RED because child `cmd.exe` saw empty `%PATH%`; with minimal `PATH` normalization it reached `ifx` and failed as expected on missing `src/fortran/uel_3d_euler_beam_kernel.f90`.
|
||||||
|
- `python scripts/validate_workspace.py`: default process failed at the same environment issue; with minimal `PATH` normalization it failed at the expected missing production kernel source.
|
||||||
|
- `$env:HARNESS_FORTRAN_VALIDATION='detect'; python scripts/validate_workspace.py`: passed.
|
||||||
|
|
||||||
## Next Agent Checklist
|
## Next Agent Checklist
|
||||||
|
|
||||||
- Read `AGENTS.md`, `PLAN.md`, `PROGRESS.md`, and `WORKNOTE.md`.
|
- Read `AGENTS.md`, `PLAN.md`, `PROGRESS.md`, and `WORKNOTE.md`.
|
||||||
- Confirm no other owner is active in this file.
|
- Confirm no other owner is active in this file.
|
||||||
- Start `phases/uel-3d-euler-beam/step6.md`.
|
- Start `phases/uel-3d-euler-beam/step7.md`.
|
||||||
- Update this file when step status changes or before handing off.
|
- Update this file when step status changes or before handing off.
|
||||||
|
|||||||
@@ -11,3 +11,4 @@
|
|||||||
- PowerShell에서 기본 출력 인코딩에 따라 Korean text가 깨져 보일 수 있다. `Get-Content -Raw -Encoding UTF8 AGENTS.md`처럼 UTF-8을 명시하면 정상 확인 가능하다.
|
- PowerShell에서 기본 출력 인코딩에 따라 Korean text가 깨져 보일 수 있다. `Get-Content -Raw -Encoding UTF8 AGENTS.md`처럼 UTF-8을 명시하면 정상 확인 가능하다.
|
||||||
- `scripts/execute.py`는 phase step을 Codex subprocess로 실행하고, 각 step이 `phases/<phase>/index.json`의 status를 직접 갱신해야 한다. Step 지시문에는 이 요구가 명확해야 한다.
|
- `scripts/execute.py`는 phase step을 Codex subprocess로 실행하고, 각 step이 `phases/<phase>/index.json`의 status를 직접 갱신해야 한다. Step 지시문에는 이 요구가 명확해야 한다.
|
||||||
- `python scripts/validate_workspace.py`는 Fortran manifest가 없으면 `validate_fortran.py`에서 "No Fortran validation commands configured."를 출력하고 성공할 수 있다. 이것은 구현 전 scaffold 상태에서는 정상이다.
|
- `python scripts/validate_workspace.py`는 Fortran manifest가 없으면 `validate_fortran.py`에서 "No Fortran validation commands configured."를 출력하고 성공할 수 있다. 이것은 구현 전 scaffold 상태에서는 정상이다.
|
||||||
|
- Step 6에서 `tests/fortran/manifest.json`을 추가한 뒤 기본 `python scripts/validate_fortran.py`가 nested `cmd` lookup에서 먼저 실패했다. PowerShell/Python은 `cmd.exe`를 찾지만 child `cmd.exe`가 `%PATH%`를 빈 값으로 보았다. RED compile evidence는 `$env:PATH='C:\Windows\System32;C:\Windows;C:\Users\user\miniforge3'; C:\Users\user\miniforge3\python.exe scripts/validate_fortran.py`로 확인했으며, 이때 `ifx`가 실행되고 missing `src/fortran/uel_3d_euler_beam_kernel.f90` compile failure가 발생했다.
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# 3D Euler-Bernoulli Beam UEL RED Test Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: uel-3d-euler-beam
|
||||||
|
- source_reference_models: `docs/reference-models/uel-3d-euler-beam.md`
|
||||||
|
- status: red-evidence-recorded
|
||||||
|
- owner_agent: implementation-agent
|
||||||
|
- date: 2026-06-11
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This report records the step 6 RED evidence after adding no-Abaqus Fortran tests and `tests/fortran/manifest.json`.
|
||||||
|
|
||||||
|
Production Fortran source was not added in this step. The expected RED condition is a compile failure from missing planned production source:
|
||||||
|
|
||||||
|
- `src/fortran/uel_3d_euler_beam_kernel.f90`
|
||||||
|
- `src/fortran/uel_3d_euler_beam_abi_adapter.f90`
|
||||||
|
|
||||||
|
## Test Files Added Before Production Code
|
||||||
|
|
||||||
|
| manifest_test | source file |
|
||||||
|
| --- | --- |
|
||||||
|
| `uel_3d_euler_beam_kernel_stiffness` | `tests/fortran/uel_3d_euler_beam/test_kernel_stiffness.f90` |
|
||||||
|
| `uel_3d_euler_beam_kernel_transform_modes` | `tests/fortran/uel_3d_euler_beam/test_kernel_transform_modes.f90` |
|
||||||
|
| `uel_3d_euler_beam_abi_static` | `tests/fortran/uel_3d_euler_beam/test_abi_static.f90` |
|
||||||
|
| `uel_3d_euler_beam_invalid_inputs` | `tests/fortran/uel_3d_euler_beam/test_invalid_inputs.f90` |
|
||||||
|
| shared support | `tests/fortran/uel_3d_euler_beam/test_support.f90` |
|
||||||
|
|
||||||
|
## Command Log Summary
|
||||||
|
|
||||||
|
| order | command | exit_code | result | evidence |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1 | `python -m json.tool tests/fortran/manifest.json` | 0 | pass | manifest JSON parsed successfully |
|
||||||
|
| 2 | `python -m unittest discover -s scripts -p "test_*.py"` | 0 | pass | 56 Python harness tests passed |
|
||||||
|
| 3 | `python scripts/validate_reference_artifacts.py` | 0 | pass | reference artifact metadata validation succeeded |
|
||||||
|
| 4 | `python scripts/validate_fortran.py` | 1 | environment failure before RED | current `cmd.exe` child process sees empty `%PATH%`; nested `cmd` command is not found |
|
||||||
|
| 5 | `$env:PATH='C:\Windows\System32;C:\Windows;C:\Users\user\miniforge3'; C:\Users\user\miniforge3\python.exe scripts/validate_fortran.py` | 1 | expected RED | `ifx` reached compile and failed because `src/fortran/uel_3d_euler_beam_kernel.f90` does not exist |
|
||||||
|
| 6 | `python scripts/validate_workspace.py` | 1 | environment failure before RED | reference validation passed, then Fortran validation hit the same nested `cmd` lookup issue |
|
||||||
|
| 7 | `$env:PATH='C:\Windows\System32;C:\Windows;C:\Users\user\miniforge3'; C:\Users\user\miniforge3\python.exe scripts/validate_workspace.py` | 1 | expected RED | reference validation passed, then Fortran validation failed on missing production kernel source |
|
||||||
|
| 8 | `$env:HARNESS_FORTRAN_VALIDATION='detect'; python scripts/validate_workspace.py` | 0 | pass | reference validation passed; Fortran manifest/compiler detection mode produced no compile commands |
|
||||||
|
|
||||||
|
## RED Failure Classification
|
||||||
|
|
||||||
|
- classification: `fortran-compile`
|
||||||
|
- first implementation-owned failure after environment normalization: missing planned production source
|
||||||
|
- primary evidence tail:
|
||||||
|
|
||||||
|
```text
|
||||||
|
xfortcom: Severe: No such file or directory
|
||||||
|
... file is 'C:\git\AbaqusSubroutineDev\src\fortran\uel_3d_euler_beam_kernel.f90'
|
||||||
|
compilation aborted for C:\git\AbaqusSubroutineDev\src\fortran\uel_3d_euler_beam_kernel.f90 (code 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
The subsequent module import errors in `test_kernel_stiffness.f90` are secondary to the missing kernel module source.
|
||||||
|
|
||||||
|
## Environment Note
|
||||||
|
|
||||||
|
This Codex process can find `cmd.exe` from PowerShell and Python, but a child `cmd.exe` invoked during `validate_fortran.py` sees an empty `%PATH%` unless a minimal `PATH` is set explicitly. The normalized command above confirms that Intel oneAPI `ifx` is available through the configured oneAPI env script and that the actionable RED failure is the missing production source, not a missing compiler.
|
||||||
|
|
||||||
|
## Handoff to Step 7
|
||||||
|
|
||||||
|
Implement the minimum production Fortran needed to turn the four manifest tests GREEN:
|
||||||
|
|
||||||
|
- `src/fortran/uel_3d_euler_beam_kernel.f90`
|
||||||
|
- `src/fortran/uel_3d_euler_beam_abi_adapter.f90`
|
||||||
|
|
||||||
|
The Abaqus fixed-form `UEL` wrapper remains planned for the implementation gate but is not required to satisfy these no-Abaqus RED tests unless the step 7 plan explicitly includes it.
|
||||||
@@ -41,7 +41,8 @@
|
|||||||
{
|
{
|
||||||
"step": 6,
|
"step": 6,
|
||||||
"name": "tdd-tests",
|
"name": "tdd-tests",
|
||||||
"status": "pending"
|
"status": "completed",
|
||||||
|
"summary": "Created approved no-Abaqus Fortran manifest and test drivers under tests/fortran/uel_3d_euler_beam. Recorded RED evidence in docs/build-test-reports/uel-3d-euler-beam-red.md: Python harness and reference artifact validation passed; normalized oneAPI Fortran validation reached ifx and failed as expected because planned production kernel source is not implemented yet."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"step": 7,
|
"step": 7,
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"name": "uel_3d_euler_beam_kernel_stiffness",
|
||||||
|
"sources": [
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_support.f90",
|
||||||
|
"src/fortran/uel_3d_euler_beam_kernel.f90",
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_kernel_stiffness.f90"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "uel_3d_euler_beam_kernel_transform_modes",
|
||||||
|
"sources": [
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_support.f90",
|
||||||
|
"src/fortran/uel_3d_euler_beam_kernel.f90",
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_kernel_transform_modes.f90"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "uel_3d_euler_beam_abi_static",
|
||||||
|
"sources": [
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_support.f90",
|
||||||
|
"src/fortran/uel_3d_euler_beam_kernel.f90",
|
||||||
|
"src/fortran/uel_3d_euler_beam_abi_adapter.f90",
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_abi_static.f90"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "uel_3d_euler_beam_invalid_inputs",
|
||||||
|
"sources": [
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_support.f90",
|
||||||
|
"src/fortran/uel_3d_euler_beam_kernel.f90",
|
||||||
|
"src/fortran/uel_3d_euler_beam_abi_adapter.f90",
|
||||||
|
"tests/fortran/uel_3d_euler_beam/test_invalid_inputs.f90"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
program test_abi_static
|
||||||
|
use uel_3d_euler_beam_test_support
|
||||||
|
use uel_3d_euler_beam_kernel, only: &
|
||||||
|
UEL3DEB_OK, uel3deb_global_stiffness
|
||||||
|
use uel_3d_euler_beam_abi_adapter, only: uel3deb_abi_static
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
call test_static_full_contribution()
|
||||||
|
call test_stiffness_only_and_residual_only()
|
||||||
|
write(*, '(A)') 'PASS uel_3d_euler_beam_abi_static'
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine valid_problem(coords, props, u)
|
||||||
|
real(dp), intent(out) :: coords(3, 2)
|
||||||
|
real(dp), intent(out) :: props(9)
|
||||||
|
real(dp), intent(out) :: u(12)
|
||||||
|
|
||||||
|
coords(:, 1) = [0.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
coords(:, 2) = [2.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
props = [210.0e9_dp, 80.0e9_dp, 3.0e-3_dp, 4.0e-6_dp, 7.0e-6_dp, &
|
||||||
|
2.5e-6_dp, 0.0_dp, 1.0_dp, 0.0_dp]
|
||||||
|
u = [1.0e-4_dp, -2.0e-4_dp, 3.0e-4_dp, 4.0e-5_dp, -5.0e-5_dp, &
|
||||||
|
6.0e-5_dp, -7.0e-4_dp, 8.0e-4_dp, -9.0e-4_dp, 1.0e-4_dp, &
|
||||||
|
-1.1e-4_dp, 1.2e-4_dp]
|
||||||
|
end subroutine valid_problem
|
||||||
|
|
||||||
|
subroutine expected_outputs(coords, props, u, expected_k, expected_rhs)
|
||||||
|
real(dp), intent(in) :: coords(3, 2)
|
||||||
|
real(dp), intent(in) :: props(9)
|
||||||
|
real(dp), intent(in) :: u(12)
|
||||||
|
real(dp), intent(out) :: expected_k(12, 12)
|
||||||
|
real(dp), intent(out) :: expected_rhs(12)
|
||||||
|
real(dp) :: transform(12, 12)
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call uel3deb_global_stiffness(coords, props, expected_k, transform, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'expected K status')
|
||||||
|
expected_rhs = -matmul(expected_k, u)
|
||||||
|
end subroutine expected_outputs
|
||||||
|
|
||||||
|
subroutine call_adapter(lflags3, rhs, amatrx, energy, pnewdt, status)
|
||||||
|
integer, intent(in) :: lflags3
|
||||||
|
real(dp), intent(out) :: rhs(12, 1)
|
||||||
|
real(dp), intent(out) :: amatrx(12, 12)
|
||||||
|
real(dp), intent(out) :: energy(8)
|
||||||
|
real(dp), intent(inout) :: pnewdt
|
||||||
|
integer, intent(out) :: status
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: u(12)
|
||||||
|
integer :: lflags(5)
|
||||||
|
integer :: jprops(1)
|
||||||
|
|
||||||
|
call valid_problem(coords, props, u)
|
||||||
|
rhs = 999.0_dp
|
||||||
|
amatrx = 999.0_dp
|
||||||
|
energy = 999.0_dp
|
||||||
|
lflags = 0
|
||||||
|
lflags(2) = 0
|
||||||
|
lflags(3) = lflags3
|
||||||
|
jprops = 0
|
||||||
|
|
||||||
|
call uel3deb_abi_static(rhs, amatrx, energy, 12, 1, 0, props, 9, coords, &
|
||||||
|
3, 2, u, lflags, 12, 0, pnewdt, jprops, 0, status)
|
||||||
|
end subroutine call_adapter
|
||||||
|
|
||||||
|
subroutine test_static_full_contribution()
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: u(12)
|
||||||
|
real(dp) :: rhs(12, 1)
|
||||||
|
real(dp) :: amatrx(12, 12)
|
||||||
|
real(dp) :: energy(8)
|
||||||
|
real(dp) :: expected_k(12, 12)
|
||||||
|
real(dp) :: expected_rhs(12)
|
||||||
|
real(dp) :: pnewdt
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call valid_problem(coords, props, u)
|
||||||
|
call expected_outputs(coords, props, u, expected_k, expected_rhs)
|
||||||
|
|
||||||
|
pnewdt = 0.25_dp
|
||||||
|
call call_adapter(1, rhs, amatrx, energy, pnewdt, status)
|
||||||
|
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'NOA-A-AMATRX-001 status LFLAGS3=1')
|
||||||
|
call assert_matrix_close(amatrx, expected_k, tol_stiff, 'NOA-A-AMATRX-001 K')
|
||||||
|
call assert_vector_close(rhs(:, 1), expected_rhs, tol_vector, 'NOA-A-RHS-001 RHS')
|
||||||
|
call assert_vector_close(energy, spread(0.0_dp, 1, 8), tol_vector, 'NOA-A-ENERGY-001 ENERGY')
|
||||||
|
call assert_close(pnewdt, 0.25_dp, tol_vector, 'NOA-A-ENERGY-001 PNEWDT')
|
||||||
|
end subroutine test_static_full_contribution
|
||||||
|
|
||||||
|
subroutine test_stiffness_only_and_residual_only()
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: u(12)
|
||||||
|
real(dp) :: rhs(12, 1)
|
||||||
|
real(dp) :: amatrx(12, 12)
|
||||||
|
real(dp) :: energy(8)
|
||||||
|
real(dp) :: expected_k(12, 12)
|
||||||
|
real(dp) :: expected_rhs(12)
|
||||||
|
real(dp) :: zeros12(12)
|
||||||
|
real(dp) :: zeros_k(12, 12)
|
||||||
|
real(dp) :: pnewdt
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call valid_problem(coords, props, u)
|
||||||
|
call expected_outputs(coords, props, u, expected_k, expected_rhs)
|
||||||
|
zeros12 = 0.0_dp
|
||||||
|
zeros_k = 0.0_dp
|
||||||
|
|
||||||
|
pnewdt = 0.5_dp
|
||||||
|
call call_adapter(2, rhs, amatrx, energy, pnewdt, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'NOA-A-AMATRX-001 status LFLAGS3=2')
|
||||||
|
call assert_matrix_close(amatrx, expected_k, tol_stiff, 'NOA-A-AMATRX-001 K only')
|
||||||
|
call assert_vector_close(rhs(:, 1), zeros12, tol_vector, 'NOA-A-AMATRX-001 zero RHS')
|
||||||
|
call assert_close(pnewdt, 0.5_dp, tol_vector, 'NOA-A-ENERGY-001 PNEWDT K only')
|
||||||
|
|
||||||
|
pnewdt = 0.75_dp
|
||||||
|
call call_adapter(5, rhs, amatrx, energy, pnewdt, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'NOA-A-RHS-001 status LFLAGS3=5')
|
||||||
|
call assert_matrix_close(amatrx, zeros_k, tol_stiff, 'NOA-A-RHS-001 zero AMATRX')
|
||||||
|
call assert_vector_close(rhs(:, 1), expected_rhs, tol_vector, 'NOA-A-RHS-001 RHS only')
|
||||||
|
call assert_close(pnewdt, 0.75_dp, tol_vector, 'NOA-A-ENERGY-001 PNEWDT RHS only')
|
||||||
|
end subroutine test_stiffness_only_and_residual_only
|
||||||
|
|
||||||
|
end program test_abi_static
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
program test_invalid_inputs
|
||||||
|
use ieee_arithmetic, only: ieee_quiet_nan, ieee_value
|
||||||
|
use uel_3d_euler_beam_test_support
|
||||||
|
use uel_3d_euler_beam_kernel, only: &
|
||||||
|
UEL3DEB_E001_NDOFEL, UEL3DEB_E002_NNODE, UEL3DEB_E003_MCRD, &
|
||||||
|
UEL3DEB_E004_NPROPS, UEL3DEB_E005_NJPROP, UEL3DEB_E006_NSVARS, &
|
||||||
|
UEL3DEB_E007_NRHS, UEL3DEB_E008_MLVARX, UEL3DEB_E009_NONFINITE, &
|
||||||
|
UEL3DEB_E010_NONPOSITIVE_PROPERTY, UEL3DEB_E011_ZERO_LENGTH, &
|
||||||
|
UEL3DEB_E012_ZERO_ORIENTATION, UEL3DEB_E013_PARALLEL_ORIENTATION, &
|
||||||
|
UEL3DEB_E014_LFLAGS2, UEL3DEB_E015_LFLAGS3, UEL3DEB_E016_NDLOAD, &
|
||||||
|
uel3deb_validate_kernel_inputs
|
||||||
|
use uel_3d_euler_beam_abi_adapter, only: uel3deb_abi_static
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
call test_kernel_physical_diagnostics()
|
||||||
|
call test_adapter_shape_and_request_diagnostics()
|
||||||
|
write(*, '(A)') 'PASS uel_3d_euler_beam_invalid_inputs'
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine valid_kernel_inputs(coords, props)
|
||||||
|
real(dp), intent(out) :: coords(3, 2)
|
||||||
|
real(dp), intent(out) :: props(9)
|
||||||
|
|
||||||
|
coords(:, 1) = [0.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
coords(:, 2) = [2.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
props = [210.0e9_dp, 80.0e9_dp, 3.0e-3_dp, 4.0e-6_dp, 7.0e-6_dp, &
|
||||||
|
2.5e-6_dp, 0.0_dp, 1.0_dp, 0.0_dp]
|
||||||
|
end subroutine valid_kernel_inputs
|
||||||
|
|
||||||
|
subroutine test_kernel_physical_diagnostics()
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: props(9)
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call valid_kernel_inputs(coords, props)
|
||||||
|
coords(1, 1) = ieee_value(coords(1, 1), ieee_quiet_nan)
|
||||||
|
call uel3deb_validate_kernel_inputs(coords, props, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_E009_NONFINITE, 'NOA-I-PHYS-001 nonfinite coordinate')
|
||||||
|
|
||||||
|
call valid_kernel_inputs(coords, props)
|
||||||
|
props(1) = -1.0_dp
|
||||||
|
call uel3deb_validate_kernel_inputs(coords, props, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_E010_NONPOSITIVE_PROPERTY, 'NOA-I-PHYS-001 nonpositive E')
|
||||||
|
|
||||||
|
call valid_kernel_inputs(coords, props)
|
||||||
|
coords(:, 2) = coords(:, 1)
|
||||||
|
call uel3deb_validate_kernel_inputs(coords, props, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_E011_ZERO_LENGTH, 'NOA-I-PHYS-001 zero length')
|
||||||
|
|
||||||
|
call valid_kernel_inputs(coords, props)
|
||||||
|
props(7:9) = [0.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
call uel3deb_validate_kernel_inputs(coords, props, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_E012_ZERO_ORIENTATION, 'NOA-I-PHYS-001 zero orientation')
|
||||||
|
|
||||||
|
call valid_kernel_inputs(coords, props)
|
||||||
|
props(7:9) = [1.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
call uel3deb_validate_kernel_inputs(coords, props, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_E013_PARALLEL_ORIENTATION, 'NOA-I-PHYS-001 parallel orientation')
|
||||||
|
end subroutine test_kernel_physical_diagnostics
|
||||||
|
|
||||||
|
subroutine test_adapter_shape_and_request_diagnostics()
|
||||||
|
call expect_adapter_status(11, 1, 0, 9, 3, 2, 12, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E001_NDOFEL, 'NOA-I-SHAPE-001 NDOFEL')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 3, 1, 12, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E002_NNODE, 'NOA-I-SHAPE-001 NNODE')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 2, 2, 12, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E003_MCRD, 'NOA-I-SHAPE-001 MCRD')
|
||||||
|
call expect_adapter_status(12, 1, 0, 8, 3, 2, 12, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E004_NPROPS, 'NOA-I-SHAPE-001 NPROPS')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 3, 2, 12, 0, 1, 0, 1, &
|
||||||
|
UEL3DEB_E005_NJPROP, 'NOA-I-SHAPE-001 NJPROP')
|
||||||
|
call expect_adapter_status(12, 1, 1, 9, 3, 2, 12, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E006_NSVARS, 'NOA-I-SHAPE-001 NSVARS')
|
||||||
|
call expect_adapter_status(12, 2, 0, 9, 3, 2, 12, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E007_NRHS, 'NOA-I-SHAPE-001 NRHS')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 3, 2, 11, 0, 0, 0, 1, &
|
||||||
|
UEL3DEB_E008_MLVARX, 'NOA-I-SHAPE-001 MLVARX')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 3, 2, 12, 0, 0, 1, 1, &
|
||||||
|
UEL3DEB_E014_LFLAGS2, 'NOA-I-LFLAGS-001 LFLAGS2')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 3, 2, 12, 0, 0, 0, 3, &
|
||||||
|
UEL3DEB_E015_LFLAGS3, 'NOA-I-LFLAGS-001 LFLAGS3')
|
||||||
|
call expect_adapter_status(12, 1, 0, 9, 3, 2, 12, 1, 0, 0, 1, &
|
||||||
|
UEL3DEB_E016_NDLOAD, 'NOA-I-LFLAGS-001 NDLOAD')
|
||||||
|
end subroutine test_adapter_shape_and_request_diagnostics
|
||||||
|
|
||||||
|
subroutine expect_adapter_status(ndofel, nrhs, nsvars, nprops, mcrd, nnode, &
|
||||||
|
mlvarx, ndload, njprop, lflag2, lflag3, &
|
||||||
|
expected_status, message)
|
||||||
|
integer, intent(in) :: ndofel
|
||||||
|
integer, intent(in) :: nrhs
|
||||||
|
integer, intent(in) :: nsvars
|
||||||
|
integer, intent(in) :: nprops
|
||||||
|
integer, intent(in) :: mcrd
|
||||||
|
integer, intent(in) :: nnode
|
||||||
|
integer, intent(in) :: mlvarx
|
||||||
|
integer, intent(in) :: ndload
|
||||||
|
integer, intent(in) :: njprop
|
||||||
|
integer, intent(in) :: lflag2
|
||||||
|
integer, intent(in) :: lflag3
|
||||||
|
integer, intent(in) :: expected_status
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: rhs(12, 2)
|
||||||
|
real(dp) :: amatrx(12, 12)
|
||||||
|
real(dp) :: energy(8)
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: u(12)
|
||||||
|
real(dp) :: pnewdt
|
||||||
|
integer :: lflags(5)
|
||||||
|
integer :: jprops(1)
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call valid_kernel_inputs(coords, props)
|
||||||
|
rhs = 0.0_dp
|
||||||
|
amatrx = 0.0_dp
|
||||||
|
energy = 0.0_dp
|
||||||
|
u = 0.0_dp
|
||||||
|
pnewdt = 1.0_dp
|
||||||
|
lflags = 0
|
||||||
|
lflags(2) = lflag2
|
||||||
|
lflags(3) = lflag3
|
||||||
|
jprops = 0
|
||||||
|
|
||||||
|
call uel3deb_abi_static(rhs, amatrx, energy, ndofel, nrhs, nsvars, props, &
|
||||||
|
nprops, coords, mcrd, nnode, u, lflags, mlvarx, &
|
||||||
|
ndload, pnewdt, jprops, njprop, status)
|
||||||
|
call assert_equal_int(status, expected_status, message)
|
||||||
|
end subroutine expect_adapter_status
|
||||||
|
|
||||||
|
end program test_invalid_inputs
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
program test_kernel_stiffness
|
||||||
|
use uel_3d_euler_beam_test_support
|
||||||
|
use uel_3d_euler_beam_kernel, only: &
|
||||||
|
UEL3DEB_OK, uel3deb_local_stiffness
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
call test_local_stiffness_entries()
|
||||||
|
call test_analytical_responses()
|
||||||
|
write(*, '(A)') 'PASS uel_3d_euler_beam_kernel_stiffness'
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine beam_values(length, young, shear, area, iy, iz, torsion_j)
|
||||||
|
real(dp), intent(out) :: length
|
||||||
|
real(dp), intent(out) :: young
|
||||||
|
real(dp), intent(out) :: shear
|
||||||
|
real(dp), intent(out) :: area
|
||||||
|
real(dp), intent(out) :: iy
|
||||||
|
real(dp), intent(out) :: iz
|
||||||
|
real(dp), intent(out) :: torsion_j
|
||||||
|
|
||||||
|
length = 2.0_dp
|
||||||
|
young = 210.0e9_dp
|
||||||
|
shear = 80.0e9_dp
|
||||||
|
area = 3.0e-3_dp
|
||||||
|
iy = 4.0e-6_dp
|
||||||
|
iz = 7.0e-6_dp
|
||||||
|
torsion_j = 2.5e-6_dp
|
||||||
|
end subroutine beam_values
|
||||||
|
|
||||||
|
subroutine build_local(k, length, young, shear, area, iy, iz, torsion_j)
|
||||||
|
real(dp), intent(out) :: k(12, 12)
|
||||||
|
real(dp), intent(out) :: length
|
||||||
|
real(dp), intent(out) :: young
|
||||||
|
real(dp), intent(out) :: shear
|
||||||
|
real(dp), intent(out) :: area
|
||||||
|
real(dp), intent(out) :: iy
|
||||||
|
real(dp), intent(out) :: iz
|
||||||
|
real(dp), intent(out) :: torsion_j
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call beam_values(length, young, shear, area, iy, iz, torsion_j)
|
||||||
|
call uel3deb_local_stiffness(length, young, shear, area, iy, iz, torsion_j, k, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'local stiffness status')
|
||||||
|
end subroutine build_local
|
||||||
|
|
||||||
|
subroutine test_local_stiffness_entries()
|
||||||
|
real(dp) :: k(12, 12)
|
||||||
|
real(dp) :: length, young, shear, area, iy, iz, torsion_j
|
||||||
|
real(dp) :: axial, torsion, b2_12, b2_6, b2_4, b2_2
|
||||||
|
real(dp) :: b3_12, b3_6, b3_4, b3_2
|
||||||
|
|
||||||
|
call build_local(k, length, young, shear, area, iy, iz, torsion_j)
|
||||||
|
|
||||||
|
axial = young * area / length
|
||||||
|
torsion = shear * torsion_j / length
|
||||||
|
b2_12 = 12.0_dp * young * iy / length**3
|
||||||
|
b2_6 = 6.0_dp * young * iy / length**2
|
||||||
|
b2_4 = 4.0_dp * young * iy / length
|
||||||
|
b2_2 = 2.0_dp * young * iy / length
|
||||||
|
b3_12 = 12.0_dp * young * iz / length**3
|
||||||
|
b3_6 = 6.0_dp * young * iz / length**2
|
||||||
|
b3_4 = 4.0_dp * young * iz / length
|
||||||
|
b3_2 = 2.0_dp * young * iz / length
|
||||||
|
|
||||||
|
call assert_matrix_symmetric(k, tol_symmetry, 'NOA-K-SYM-001 local symmetry')
|
||||||
|
|
||||||
|
call assert_close(k(1, 1), axial, tol_stiff, 'NOA-K-STIFF-001 axial k11')
|
||||||
|
call assert_close(k(1, 7), -axial, tol_stiff, 'NOA-K-STIFF-001 axial k17')
|
||||||
|
call assert_close(k(7, 7), axial, tol_stiff, 'NOA-K-STIFF-001 axial k77')
|
||||||
|
call assert_close(k(4, 4), torsion, tol_stiff, 'NOA-K-STIFF-001 torsion k44')
|
||||||
|
call assert_close(k(4, 10), -torsion, tol_stiff, 'NOA-K-STIFF-001 torsion k4,10')
|
||||||
|
call assert_close(k(10, 10), torsion, tol_stiff, 'NOA-K-STIFF-001 torsion k10,10')
|
||||||
|
|
||||||
|
call assert_close(k(3, 3), b2_12, tol_stiff, 'NOA-K-BEND2-001 k33')
|
||||||
|
call assert_close(k(3, 5), -b2_6, tol_stiff, 'NOA-K-BEND2-001 k35')
|
||||||
|
call assert_close(k(3, 9), -b2_12, tol_stiff, 'NOA-K-BEND2-001 k39')
|
||||||
|
call assert_close(k(3, 11), -b2_6, tol_stiff, 'NOA-K-BEND2-001 k3,11')
|
||||||
|
call assert_close(k(5, 5), b2_4, tol_stiff, 'NOA-K-BEND2-001 k55')
|
||||||
|
call assert_close(k(5, 9), b2_6, tol_stiff, 'NOA-K-BEND2-001 k59')
|
||||||
|
call assert_close(k(5, 11), b2_2, tol_stiff, 'NOA-K-BEND2-001 k5,11')
|
||||||
|
call assert_close(k(11, 11), b2_4, tol_stiff, 'NOA-K-BEND2-001 k11,11')
|
||||||
|
|
||||||
|
call assert_close(k(2, 2), b3_12, tol_stiff, 'NOA-K-BEND3-001 k22')
|
||||||
|
call assert_close(k(2, 6), b3_6, tol_stiff, 'NOA-K-BEND3-001 k26')
|
||||||
|
call assert_close(k(2, 8), -b3_12, tol_stiff, 'NOA-K-BEND3-001 k28')
|
||||||
|
call assert_close(k(2, 12), b3_6, tol_stiff, 'NOA-K-BEND3-001 k2,12')
|
||||||
|
call assert_close(k(6, 6), b3_4, tol_stiff, 'NOA-K-BEND3-001 k66')
|
||||||
|
call assert_close(k(6, 8), -b3_6, tol_stiff, 'NOA-K-BEND3-001 k68')
|
||||||
|
call assert_close(k(6, 12), b3_2, tol_stiff, 'NOA-K-BEND3-001 k6,12')
|
||||||
|
call assert_close(k(12, 12), b3_4, tol_stiff, 'NOA-K-BEND3-001 k12,12')
|
||||||
|
call assert_close(k(2, 3), 0.0_dp, tol_stiff, 'NOA-K-STIFF-001 uncoupled k23')
|
||||||
|
end subroutine test_local_stiffness_entries
|
||||||
|
|
||||||
|
subroutine test_analytical_responses()
|
||||||
|
real(dp) :: k(12, 12)
|
||||||
|
real(dp) :: force(12)
|
||||||
|
real(dp) :: u(12)
|
||||||
|
real(dp) :: length, young, shear, area, iy, iz, torsion_j
|
||||||
|
real(dp) :: axial, torsion, b2_12, b3_12
|
||||||
|
|
||||||
|
call build_local(k, length, young, shear, area, iy, iz, torsion_j)
|
||||||
|
|
||||||
|
axial = young * area / length
|
||||||
|
torsion = shear * torsion_j / length
|
||||||
|
b2_12 = 12.0_dp * young * iy / length**3
|
||||||
|
b3_12 = 12.0_dp * young * iz / length**3
|
||||||
|
|
||||||
|
u = 0.0_dp
|
||||||
|
u(7) = 1.0e-2_dp
|
||||||
|
force = matmul(k, u)
|
||||||
|
call assert_close(force(1), -axial * u(7), tol_vector, 'NOA-K-STIFF-002 f1')
|
||||||
|
call assert_close(force(7), axial * u(7), tol_vector, 'NOA-K-STIFF-002 f7')
|
||||||
|
|
||||||
|
u = 0.0_dp
|
||||||
|
u(10) = 2.0e-2_dp
|
||||||
|
force = matmul(k, u)
|
||||||
|
call assert_close(force(4), -torsion * u(10), tol_vector, 'NOA-K-STIFF-003 m1')
|
||||||
|
call assert_close(force(10), torsion * u(10), tol_vector, 'NOA-K-STIFF-003 m2')
|
||||||
|
|
||||||
|
u = 0.0_dp
|
||||||
|
u(9) = 1.0e-2_dp
|
||||||
|
force = matmul(k, u)
|
||||||
|
call assert_close(force(3), -b2_12 * u(9), tol_vector, 'NOA-K-BEND2-001 f3')
|
||||||
|
call assert_close(force(9), b2_12 * u(9), tol_vector, 'NOA-K-BEND2-001 f9')
|
||||||
|
|
||||||
|
u = 0.0_dp
|
||||||
|
u(8) = 1.0e-2_dp
|
||||||
|
force = matmul(k, u)
|
||||||
|
call assert_close(force(2), -b3_12 * u(8), tol_vector, 'NOA-K-BEND3-001 f2')
|
||||||
|
call assert_close(force(8), b3_12 * u(8), tol_vector, 'NOA-K-BEND3-001 f8')
|
||||||
|
end subroutine test_analytical_responses
|
||||||
|
|
||||||
|
end program test_kernel_stiffness
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
program test_kernel_transform_modes
|
||||||
|
use uel_3d_euler_beam_test_support
|
||||||
|
use uel_3d_euler_beam_kernel, only: &
|
||||||
|
UEL3DEB_OK, uel3deb_global_stiffness, uel3deb_local_stiffness
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
call test_identity_and_rotated_transform()
|
||||||
|
call test_rigid_body_modes()
|
||||||
|
call test_reversed_node_order()
|
||||||
|
write(*, '(A)') 'PASS uel_3d_euler_beam_kernel_transform_modes'
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine valid_props(props)
|
||||||
|
real(dp), intent(out) :: props(9)
|
||||||
|
|
||||||
|
props = [210.0e9_dp, 80.0e9_dp, 3.0e-3_dp, 4.0e-6_dp, 7.0e-6_dp, &
|
||||||
|
2.5e-6_dp, 0.0_dp, 1.0_dp, 0.0_dp]
|
||||||
|
end subroutine valid_props
|
||||||
|
|
||||||
|
subroutine fill_block_transform(rotation, transform)
|
||||||
|
real(dp), intent(in) :: rotation(3, 3)
|
||||||
|
real(dp), intent(out) :: transform(12, 12)
|
||||||
|
integer :: block
|
||||||
|
integer :: i
|
||||||
|
integer :: j
|
||||||
|
|
||||||
|
transform = 0.0_dp
|
||||||
|
do block = 0, 3
|
||||||
|
do i = 1, 3
|
||||||
|
do j = 1, 3
|
||||||
|
transform(3 * block + i, 3 * block + j) = rotation(i, j)
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
end subroutine fill_block_transform
|
||||||
|
|
||||||
|
subroutine test_identity_and_rotated_transform()
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: k_local(12, 12)
|
||||||
|
real(dp) :: k_global(12, 12)
|
||||||
|
real(dp) :: transform(12, 12)
|
||||||
|
real(dp) :: expected(12, 12)
|
||||||
|
real(dp) :: expected_transform(12, 12)
|
||||||
|
real(dp) :: rotation(3, 3)
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call valid_props(props)
|
||||||
|
coords(:, 1) = [0.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
coords(:, 2) = [2.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
|
||||||
|
call uel3deb_local_stiffness(2.0_dp, props(1), props(2), props(3), props(4), &
|
||||||
|
props(5), props(6), k_local, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'identity local stiffness status')
|
||||||
|
call uel3deb_global_stiffness(coords, props, k_global, transform, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'identity global stiffness status')
|
||||||
|
call set_identity(expected_transform)
|
||||||
|
call assert_matrix_close(transform, expected_transform, tol_stiff, 'NOA-K-ROT-001 identity T')
|
||||||
|
call assert_matrix_close(k_global, k_local, tol_stiff, 'NOA-K-ROT-001 identity K')
|
||||||
|
|
||||||
|
props(7:9) = [0.0_dp, 0.0_dp, 1.0_dp]
|
||||||
|
coords(:, 2) = [0.0_dp, 2.0_dp, 0.0_dp]
|
||||||
|
call uel3deb_global_stiffness(coords, props, k_global, transform, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'rotated global stiffness status')
|
||||||
|
|
||||||
|
rotation = 0.0_dp
|
||||||
|
rotation(1, 2) = 1.0_dp
|
||||||
|
rotation(2, 3) = 1.0_dp
|
||||||
|
rotation(3, 1) = 1.0_dp
|
||||||
|
call fill_block_transform(rotation, expected_transform)
|
||||||
|
expected = matmul(transpose(expected_transform), matmul(k_local, expected_transform))
|
||||||
|
call assert_matrix_close(transform, expected_transform, tol_stiff, 'NOA-K-ROT-001 rotated T')
|
||||||
|
call assert_matrix_close(k_global, expected, tol_stiff, 'NOA-K-ROT-001 rotated K')
|
||||||
|
call assert_matrix_symmetric(k_global, tol_symmetry, 'NOA-K-SYM-001 global symmetry')
|
||||||
|
end subroutine test_identity_and_rotated_transform
|
||||||
|
|
||||||
|
subroutine test_rigid_body_modes()
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: coords(3, 2)
|
||||||
|
real(dp) :: k_global(12, 12)
|
||||||
|
real(dp) :: transform(12, 12)
|
||||||
|
real(dp) :: mode(12)
|
||||||
|
integer :: status
|
||||||
|
|
||||||
|
call valid_props(props)
|
||||||
|
coords(:, 1) = [0.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
coords(:, 2) = [2.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
call uel3deb_global_stiffness(coords, props, k_global, transform, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'rigid mode stiffness status')
|
||||||
|
|
||||||
|
mode = 0.0_dp
|
||||||
|
mode([1, 7]) = 1.0_dp
|
||||||
|
call assert_rigid_mode(k_global, mode, 'NOA-K-RBM-001 rigid U1')
|
||||||
|
|
||||||
|
mode = 0.0_dp
|
||||||
|
mode([2, 8]) = 1.0_dp
|
||||||
|
call assert_rigid_mode(k_global, mode, 'NOA-K-RBM-001 rigid U2')
|
||||||
|
|
||||||
|
mode = 0.0_dp
|
||||||
|
mode([3, 9]) = 1.0_dp
|
||||||
|
call assert_rigid_mode(k_global, mode, 'NOA-K-RBM-001 rigid U3')
|
||||||
|
|
||||||
|
mode = 0.0_dp
|
||||||
|
mode([4, 10]) = 1.0_dp
|
||||||
|
call assert_rigid_mode(k_global, mode, 'NOA-K-RBM-001 rigid UR1')
|
||||||
|
|
||||||
|
mode = 0.0_dp
|
||||||
|
mode(3) = 0.0_dp
|
||||||
|
mode(5) = 1.0_dp
|
||||||
|
mode(9) = -2.0_dp
|
||||||
|
mode(11) = 1.0_dp
|
||||||
|
call assert_rigid_mode(k_global, mode, 'NOA-K-RBM-001 rigid UR2')
|
||||||
|
|
||||||
|
mode = 0.0_dp
|
||||||
|
mode(2) = 0.0_dp
|
||||||
|
mode(6) = 1.0_dp
|
||||||
|
mode(8) = 2.0_dp
|
||||||
|
mode(12) = 1.0_dp
|
||||||
|
call assert_rigid_mode(k_global, mode, 'NOA-K-RBM-001 rigid UR3')
|
||||||
|
end subroutine test_rigid_body_modes
|
||||||
|
|
||||||
|
subroutine assert_rigid_mode(k_global, mode, message)
|
||||||
|
real(dp), intent(in) :: k_global(12, 12)
|
||||||
|
real(dp), intent(in) :: mode(12)
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: residual(12)
|
||||||
|
real(dp) :: limit
|
||||||
|
|
||||||
|
residual = matmul(k_global, mode)
|
||||||
|
limit = tol_vector * max(1.0_dp, max_abs_matrix(k_global) * max_abs_vector(mode))
|
||||||
|
call assert_vector_norm_le(residual, limit, message)
|
||||||
|
end subroutine assert_rigid_mode
|
||||||
|
|
||||||
|
subroutine test_reversed_node_order()
|
||||||
|
real(dp) :: props(9)
|
||||||
|
real(dp) :: coords_forward(3, 2)
|
||||||
|
real(dp) :: coords_reversed(3, 2)
|
||||||
|
real(dp) :: k_forward(12, 12)
|
||||||
|
real(dp) :: k_reversed(12, 12)
|
||||||
|
real(dp) :: transform(12, 12)
|
||||||
|
real(dp) :: expected_reversed(12, 12)
|
||||||
|
integer :: status
|
||||||
|
integer :: i
|
||||||
|
integer :: j
|
||||||
|
integer :: permutation(12)
|
||||||
|
|
||||||
|
call valid_props(props)
|
||||||
|
coords_forward(:, 1) = [0.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
coords_forward(:, 2) = [2.0_dp, 0.0_dp, 0.0_dp]
|
||||||
|
coords_reversed(:, 1) = coords_forward(:, 2)
|
||||||
|
coords_reversed(:, 2) = coords_forward(:, 1)
|
||||||
|
|
||||||
|
call uel3deb_global_stiffness(coords_forward, props, k_forward, transform, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'forward node stiffness status')
|
||||||
|
call uel3deb_global_stiffness(coords_reversed, props, k_reversed, transform, status)
|
||||||
|
call assert_equal_int(status, UEL3DEB_OK, 'reversed node stiffness status')
|
||||||
|
|
||||||
|
permutation = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
|
||||||
|
do i = 1, 12
|
||||||
|
do j = 1, 12
|
||||||
|
expected_reversed(i, j) = k_forward(permutation(i), permutation(j))
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
call assert_matrix_close(k_reversed, expected_reversed, tol_stiff, 'NOA-K-REVNODE-001')
|
||||||
|
end subroutine test_reversed_node_order
|
||||||
|
|
||||||
|
end program test_kernel_transform_modes
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
module uel_3d_euler_beam_test_support
|
||||||
|
use iso_fortran_env, only: real64
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
integer, parameter :: dp = real64
|
||||||
|
real(dp), parameter :: tol_stiff = 1.0e-10_dp
|
||||||
|
real(dp), parameter :: tol_vector = 1.0e-10_dp
|
||||||
|
real(dp), parameter :: tol_symmetry = 1.0e-12_dp
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine fail_test(message)
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
|
||||||
|
write(*, '(A)') 'FAIL: ' // trim(message)
|
||||||
|
error stop 1
|
||||||
|
end subroutine fail_test
|
||||||
|
|
||||||
|
subroutine assert_true(condition, message)
|
||||||
|
logical, intent(in) :: condition
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
|
||||||
|
if (.not. condition) call fail_test(message)
|
||||||
|
end subroutine assert_true
|
||||||
|
|
||||||
|
subroutine assert_equal_int(actual, expected, message)
|
||||||
|
integer, intent(in) :: actual
|
||||||
|
integer, intent(in) :: expected
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
|
||||||
|
if (actual /= expected) then
|
||||||
|
write(*, *) 'actual=', actual, ' expected=', expected
|
||||||
|
call fail_test(message)
|
||||||
|
end if
|
||||||
|
end subroutine assert_equal_int
|
||||||
|
|
||||||
|
subroutine assert_close(actual, expected, tolerance, message)
|
||||||
|
real(dp), intent(in) :: actual
|
||||||
|
real(dp), intent(in) :: expected
|
||||||
|
real(dp), intent(in) :: tolerance
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: limit
|
||||||
|
|
||||||
|
limit = tolerance * max(1.0_dp, abs(expected))
|
||||||
|
if (abs(actual - expected) > limit) then
|
||||||
|
write(*, *) 'actual=', actual, ' expected=', expected, ' limit=', limit
|
||||||
|
call fail_test(message)
|
||||||
|
end if
|
||||||
|
end subroutine assert_close
|
||||||
|
|
||||||
|
function max_abs_matrix(values) result(max_abs)
|
||||||
|
real(dp), intent(in) :: values(:, :)
|
||||||
|
real(dp) :: max_abs
|
||||||
|
|
||||||
|
max_abs = maxval(abs(values))
|
||||||
|
end function max_abs_matrix
|
||||||
|
|
||||||
|
function max_abs_vector(values) result(max_abs)
|
||||||
|
real(dp), intent(in) :: values(:)
|
||||||
|
real(dp) :: max_abs
|
||||||
|
|
||||||
|
max_abs = maxval(abs(values))
|
||||||
|
end function max_abs_vector
|
||||||
|
|
||||||
|
subroutine assert_matrix_close(actual, expected, tolerance, message)
|
||||||
|
real(dp), intent(in) :: actual(:, :)
|
||||||
|
real(dp), intent(in) :: expected(:, :)
|
||||||
|
real(dp), intent(in) :: tolerance
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: diff
|
||||||
|
real(dp) :: limit
|
||||||
|
|
||||||
|
call assert_true(all(shape(actual) == shape(expected)), trim(message) // ' shape')
|
||||||
|
diff = maxval(abs(actual - expected))
|
||||||
|
limit = tolerance * max(1.0_dp, max_abs_matrix(expected))
|
||||||
|
if (diff > limit) then
|
||||||
|
write(*, *) 'max matrix diff=', diff, ' limit=', limit
|
||||||
|
call fail_test(message)
|
||||||
|
end if
|
||||||
|
end subroutine assert_matrix_close
|
||||||
|
|
||||||
|
subroutine assert_vector_close(actual, expected, tolerance, message)
|
||||||
|
real(dp), intent(in) :: actual(:)
|
||||||
|
real(dp), intent(in) :: expected(:)
|
||||||
|
real(dp), intent(in) :: tolerance
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: diff
|
||||||
|
real(dp) :: limit
|
||||||
|
|
||||||
|
call assert_true(size(actual) == size(expected), trim(message) // ' size')
|
||||||
|
diff = maxval(abs(actual - expected))
|
||||||
|
limit = tolerance * max(1.0_dp, max_abs_vector(expected))
|
||||||
|
if (diff > limit) then
|
||||||
|
write(*, *) 'max vector diff=', diff, ' limit=', limit
|
||||||
|
call fail_test(message)
|
||||||
|
end if
|
||||||
|
end subroutine assert_vector_close
|
||||||
|
|
||||||
|
subroutine assert_vector_norm_le(actual, limit, message)
|
||||||
|
real(dp), intent(in) :: actual(:)
|
||||||
|
real(dp), intent(in) :: limit
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: norm_inf
|
||||||
|
|
||||||
|
norm_inf = max_abs_vector(actual)
|
||||||
|
if (norm_inf > limit) then
|
||||||
|
write(*, *) 'max vector norm=', norm_inf, ' limit=', limit
|
||||||
|
call fail_test(message)
|
||||||
|
end if
|
||||||
|
end subroutine assert_vector_norm_le
|
||||||
|
|
||||||
|
subroutine assert_matrix_symmetric(values, tolerance, message)
|
||||||
|
real(dp), intent(in) :: values(:, :)
|
||||||
|
real(dp), intent(in) :: tolerance
|
||||||
|
character(len=*), intent(in) :: message
|
||||||
|
real(dp) :: diff
|
||||||
|
real(dp) :: limit
|
||||||
|
|
||||||
|
call assert_true(size(values, 1) == size(values, 2), trim(message) // ' square')
|
||||||
|
diff = maxval(abs(values - transpose(values)))
|
||||||
|
limit = tolerance * max(1.0_dp, max_abs_matrix(values))
|
||||||
|
if (diff > limit) then
|
||||||
|
write(*, *) 'symmetry diff=', diff, ' limit=', limit
|
||||||
|
call fail_test(message)
|
||||||
|
end if
|
||||||
|
end subroutine assert_matrix_symmetric
|
||||||
|
|
||||||
|
subroutine set_identity(values)
|
||||||
|
real(dp), intent(out) :: values(:, :)
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
values = 0.0_dp
|
||||||
|
do i = 1, min(size(values, 1), size(values, 2))
|
||||||
|
values(i, i) = 1.0_dp
|
||||||
|
end do
|
||||||
|
end subroutine set_identity
|
||||||
|
|
||||||
|
end module uel_3d_euler_beam_test_support
|
||||||
Reference in New Issue
Block a user