diff --git a/.coverage b/.coverage new file mode 100644 index 00000000..81c5338b Binary files /dev/null and b/.coverage differ diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f5efa662..cc448951 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -99,7 +99,7 @@ jobs: poetry run mypy - name: Run FEM tests with pytest run: | - poetry run pytest --pspec tests/ + poetry run pytest publish: name: Publish to PyPI needs: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b3b6f9d4..22c268c4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -32,7 +32,7 @@ jobs: poetry run mypy -p anastruct - name: Run FEM tests with pytest run: | - poetry run pytest --pspec tests/ + poetry run pytest run_tests: name: Run FEM Testing Suite on Multiple Python Versions @@ -57,4 +57,4 @@ jobs: - name: Run FEM tests with pytest run: | - poetry run pytest --pspec tests/ + poetry run pytest diff --git a/.vscode/settings.json b/.vscode/settings.json index 422d0e7e..7f88d734 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -44,5 +44,7 @@ "pylint.severity": { "refactor": "Information" }, - "python.analysis.typeCheckingMode": "basic" + "python.analysis.typeCheckingMode": "basic", + "python.testing.pytestEnabled": true, + "testing.coverageToolbarEnabled": true } diff --git a/anastruct/fem/examples/__init__.py b/examples/__init__.py similarity index 100% rename from anastruct/fem/examples/__init__.py rename to examples/__init__.py diff --git a/anastruct/fem/examples/ex_1.py b/examples/ex_1.py similarity index 100% rename from anastruct/fem/examples/ex_1.py rename to examples/ex_1.py diff --git a/anastruct/fem/examples/ex_10_dead_load.py b/examples/ex_10_dead_load.py similarity index 100% rename from anastruct/fem/examples/ex_10_dead_load.py rename to examples/ex_10_dead_load.py diff --git a/anastruct/fem/examples/ex_11.py b/examples/ex_11.py similarity index 100% rename from anastruct/fem/examples/ex_11.py rename to examples/ex_11.py diff --git a/anastruct/fem/examples/ex_12.py b/examples/ex_12.py similarity index 100% rename from anastruct/fem/examples/ex_12.py rename to examples/ex_12.py diff --git a/anastruct/fem/examples/ex_13.py b/examples/ex_13.py similarity index 100% rename from anastruct/fem/examples/ex_13.py rename to examples/ex_13.py diff --git a/anastruct/fem/examples/ex_14.py b/examples/ex_14.py similarity index 100% rename from anastruct/fem/examples/ex_14.py rename to examples/ex_14.py diff --git a/anastruct/fem/examples/ex_15.py b/examples/ex_15.py similarity index 100% rename from anastruct/fem/examples/ex_15.py rename to examples/ex_15.py diff --git a/anastruct/fem/examples/ex_16.py b/examples/ex_16.py similarity index 100% rename from anastruct/fem/examples/ex_16.py rename to examples/ex_16.py diff --git a/anastruct/fem/examples/ex_17_gnl.py b/examples/ex_17_gnl.py similarity index 100% rename from anastruct/fem/examples/ex_17_gnl.py rename to examples/ex_17_gnl.py diff --git a/anastruct/fem/examples/ex_18_discretize.py b/examples/ex_18_discretize.py similarity index 100% rename from anastruct/fem/examples/ex_18_discretize.py rename to examples/ex_18_discretize.py diff --git a/anastruct/fem/examples/ex_19_num_displacements.py b/examples/ex_19_num_displacements.py similarity index 100% rename from anastruct/fem/examples/ex_19_num_displacements.py rename to examples/ex_19_num_displacements.py diff --git a/anastruct/fem/examples/ex_1_2.py b/examples/ex_1_2.py similarity index 100% rename from anastruct/fem/examples/ex_1_2.py rename to examples/ex_1_2.py diff --git a/anastruct/fem/examples/ex_2.py b/examples/ex_2.py similarity index 100% rename from anastruct/fem/examples/ex_2.py rename to examples/ex_2.py diff --git a/anastruct/fem/examples/ex_20_insert_node.py b/examples/ex_20_insert_node.py similarity index 100% rename from anastruct/fem/examples/ex_20_insert_node.py rename to examples/ex_20_insert_node.py diff --git a/anastruct/fem/examples/ex_21_rotate_force.py b/examples/ex_21_rotate_force.py similarity index 100% rename from anastruct/fem/examples/ex_21_rotate_force.py rename to examples/ex_21_rotate_force.py diff --git a/anastruct/fem/examples/ex_22_loadcombination_doc.py b/examples/ex_22_loadcombination_doc.py similarity index 100% rename from anastruct/fem/examples/ex_22_loadcombination_doc.py rename to examples/ex_22_loadcombination_doc.py diff --git a/anastruct/fem/examples/ex_23_sectionbase.py b/examples/ex_23_sectionbase.py similarity index 100% rename from anastruct/fem/examples/ex_23_sectionbase.py rename to examples/ex_23_sectionbase.py diff --git a/anastruct/fem/examples/ex_24_envelope_lines.py b/examples/ex_24_envelope_lines.py similarity index 100% rename from anastruct/fem/examples/ex_24_envelope_lines.py rename to examples/ex_24_envelope_lines.py diff --git a/anastruct/fem/examples/ex_25_high_midspan_point.py b/examples/ex_25_high_midspan_point.py similarity index 100% rename from anastruct/fem/examples/ex_25_high_midspan_point.py rename to examples/ex_25_high_midspan_point.py diff --git a/anastruct/fem/examples/ex_26_deflection.py b/examples/ex_26_deflection.py similarity index 100% rename from anastruct/fem/examples/ex_26_deflection.py rename to examples/ex_26_deflection.py diff --git a/anastruct/fem/examples/ex_3.py b/examples/ex_3.py similarity index 100% rename from anastruct/fem/examples/ex_3.py rename to examples/ex_3.py diff --git a/anastruct/fem/examples/ex_4.py b/examples/ex_4.py similarity index 100% rename from anastruct/fem/examples/ex_4.py rename to examples/ex_4.py diff --git a/anastruct/fem/examples/ex_5.py b/examples/ex_5.py similarity index 100% rename from anastruct/fem/examples/ex_5.py rename to examples/ex_5.py diff --git a/anastruct/fem/examples/ex_6_fixed_hinge.py b/examples/ex_6_fixed_hinge.py similarity index 100% rename from anastruct/fem/examples/ex_6_fixed_hinge.py rename to examples/ex_6_fixed_hinge.py diff --git a/anastruct/fem/examples/ex_7_rotational_spring.py b/examples/ex_7_rotational_spring.py similarity index 100% rename from anastruct/fem/examples/ex_7_rotational_spring.py rename to examples/ex_7_rotational_spring.py diff --git a/anastruct/fem/examples/ex_8_non_linear_portal.py b/examples/ex_8_non_linear_portal.py similarity index 100% rename from anastruct/fem/examples/ex_8_non_linear_portal.py rename to examples/ex_8_non_linear_portal.py diff --git a/anastruct/fem/examples/ex_9_vertical_spring.py b/examples/ex_9_vertical_spring.py similarity index 100% rename from anastruct/fem/examples/ex_9_vertical_spring.py rename to examples/ex_9_vertical_spring.py diff --git a/anastruct/fem/examples/water_acc.ipynb b/examples/water_acc.ipynb similarity index 100% rename from anastruct/fem/examples/water_acc.ipynb rename to examples/water_acc.ipynb diff --git a/poetry.lock b/poetry.lock index 9111d8de..441831ca 100644 --- a/poetry.lock +++ b/poetry.lock @@ -446,6 +446,114 @@ mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.17.0)", " test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] +[[package]] +name = "coverage" +version = "7.12.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["test"] +files = [ + {file = "coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b"}, + {file = "coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d"}, + {file = "coverage-7.12.0-cp310-cp310-win32.whl", hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef"}, + {file = "coverage-7.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022"}, + {file = "coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f"}, + {file = "coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984"}, + {file = "coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6"}, + {file = "coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4"}, + {file = "coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc"}, + {file = "coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647"}, + {file = "coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937"}, + {file = "coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa"}, + {file = "coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a"}, + {file = "coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c"}, + {file = "coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941"}, + {file = "coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc"}, + {file = "coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8"}, + {file = "coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07"}, + {file = "coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc"}, + {file = "coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87"}, + {file = "coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455"}, + {file = "coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d"}, + {file = "coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c"}, + {file = "coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d"}, + {file = "coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92"}, + {file = "coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17"}, + {file = "coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933"}, + {file = "coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe"}, + {file = "coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d"}, + {file = "coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d"}, + {file = "coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b"}, + {file = "coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a"}, + {file = "coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291"}, + {file = "coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384"}, + {file = "coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a"}, + {file = "coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + [[package]] name = "cycler" version = "0.12.1" @@ -1582,35 +1690,39 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] -name = "pytest-describe" -version = "3.0.0" -description = "Describe-style plugin for pytest" +name = "pytest-cov" +version = "7.0.0" +description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" groups = ["test"] files = [ - {file = "pytest_describe-3.0.0-py3-none-any.whl", hash = "sha256:946d40b5d77faf4eb610b94f2d54ab8b6721cc0b313f5bfb3663fd25c6a3920a"}, - {file = "pytest_describe-3.0.0.tar.gz", hash = "sha256:50e0b7f404decaeb1b5d7bca13cbe369208d1eeffafc2802663777b195f074ff"}, + {file = "pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861"}, + {file = "pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1"}, ] [package.dependencies] -pytest = ">=6,<9" +coverage = {version = ">=7.10.6", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=7" + +[package.extras] +testing = ["process-tests", "pytest-xdist", "virtualenv"] [[package]] -name = "pytest-pspec" -version = "0.0.4" -description = "A rspec format reporter for Python ptest" +name = "pytest-describe" +version = "3.0.0" +description = "Describe-style plugin for pytest" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["test"] files = [ - {file = "pytest-pspec-0.0.4.tar.gz", hash = "sha256:5c0b0c9e964d5066cc5f2a2e1b296ad1313abbf58c4fd75014553fdf65bfe67a"}, - {file = "pytest_pspec-0.0.4-py2.py3-none-any.whl", hash = "sha256:f80cc46f8896524bfe68750f3a5324bad8d4cb5112e90004bfdaafb7248e5cfd"}, + {file = "pytest_describe-3.0.0-py3-none-any.whl", hash = "sha256:946d40b5d77faf4eb610b94f2d54ab8b6721cc0b313f5bfb3663fd25c6a3920a"}, + {file = "pytest_describe-3.0.0.tar.gz", hash = "sha256:50e0b7f404decaeb1b5d7bca13cbe369208d1eeffafc2802663777b195f074ff"}, ] [package.dependencies] -pytest = ">=3.0.0" -six = ">=1.11.0" +pytest = ">=6,<9" [[package]] name = "pytest-raises" @@ -1752,7 +1864,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev", "test"] +groups = ["main", "dev"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2086,4 +2198,4 @@ plot = ["matplotlib"] [metadata] lock-version = "2.1" python-versions = ">=3.10" -content-hash = "a83a7eb266555cc61fadc6be594492ec62f4a87de79c4b2a39f6a5ad20dd9ccd" +content-hash = "87a9ed1ffb1f3f518a442609a884b7d48039a9c5ea7b1a310e3d5431b15999fe" diff --git a/pyproject.toml b/pyproject.toml index b644ed94..f05a4bde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,8 +52,8 @@ pylint = "==4.0.2" mypy = "==1.18.2" black = { version = "==25.11.0", extras = ["jupyter"] } pytest = "==8.4.2" +pytest-cov = "==7.0.0" pytest-describe = "==3.0.0" -pytest-pspec = "==0.0.4" pytest-raises = "==0.11" [tool.poetry.group.docs] @@ -92,6 +92,11 @@ disable = [ max-line-length = 120 py-version = [3.10, 3.11, 3.12, 3.13] +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "--cov=anastruct" +required_plugins = ["pytest-raises", "pytest-describe", "pytest-cov"] + [tool.mypy] packages = "anastruct" python_version = "3.10" diff --git a/tests/fixtures/e2e_fixtures.py b/tests/fixtures/e2e_fixtures.py index 5aca504b..bfb4859c 100644 --- a/tests/fixtures/e2e_fixtures.py +++ b/tests/fixtures/e2e_fixtures.py @@ -1,19 +1,20 @@ -import pytest import numpy as np +import pytest + from anastruct import LoadCase, LoadCombination, SystemElements -from anastruct.fem.examples.ex_8_non_linear_portal import ss as SS_ex8 -from anastruct.fem.examples.ex_7_rotational_spring import ss as SS_ex7 -from anastruct.fem.examples.ex_11 import ss as SS_ex11 -from anastruct.fem.examples.ex_12 import ss as SS_ex12 -from anastruct.fem.examples.ex_13 import ss as SS_ex13 -from anastruct.fem.examples.ex_14 import ss as SS_ex14 -from anastruct.fem.examples.ex_15 import ss as SS_ex15 -from anastruct.fem.examples.ex_16 import ss as SS_ex16 -from anastruct.fem.examples.ex_17_gnl import ss as SS_ex17 -from anastruct.fem.examples.ex_18_discretize import ss as SS_ex18 -from anastruct.fem.examples.ex_19_num_displacements import ss as SS_ex19 -from anastruct.fem.examples.ex_20_insert_node import ss as SS_ex20 -from anastruct.fem.examples.ex_26_deflection import ss as SS_ex26 +from examples.ex_7_rotational_spring import ss as SS_ex7 +from examples.ex_8_non_linear_portal import ss as SS_ex8 +from examples.ex_11 import ss as SS_ex11 +from examples.ex_12 import ss as SS_ex12 +from examples.ex_13 import ss as SS_ex13 +from examples.ex_14 import ss as SS_ex14 +from examples.ex_15 import ss as SS_ex15 +from examples.ex_16 import ss as SS_ex16 +from examples.ex_17_gnl import ss as SS_ex17 +from examples.ex_18_discretize import ss as SS_ex18 +from examples.ex_19_num_displacements import ss as SS_ex19 +from examples.ex_20_insert_node import ss as SS_ex20 +from examples.ex_26_deflection import ss as SS_ex26 @pytest.fixture diff --git a/tests/pytest.ini b/tests/pytest.ini deleted file mode 100644 index 4ba1393e..00000000 --- a/tests/pytest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[pytest] -describe_prefixes = describe context -# filterwarnings = ignore::DeprecationWarning -# matplotlib throws a useless deprecation warning -required_plugins = "pytest-describe" "pytest-pspec" "pytest-raises" -# in a development environment, strongly recommend pytest-watch or pytest-watcher as well, but neither is required to run pytest \ No newline at end of file diff --git a/tests/test_analytical.py b/tests/test_analytical.py new file mode 100644 index 00000000..78edfc24 --- /dev/null +++ b/tests/test_analytical.py @@ -0,0 +1,308 @@ +import numpy as np +from pytest import approx, raises + +from anastruct import LoadCase, LoadCombination, SystemElements + +from .fixtures.e2e_fixtures import * +from .utils import pspec_context + +""" +NOTE: Several tests in this file validate that the correct numerical engineering results +occur in specific tested scenarios. These results are thereby validated against analytical +results for the same scenarios (which comes from engineering theory). Rather than comment +every single occurrence of every engineering variable, the following general definitions +apply to any tests in which these occur: +- L = total member length (typically in metres) +- l = length of individual member span +- w = peak distributed load magnitude (typically in kN/m) +- W = total distributed load (often w * l, typically in kN) +- P = concentrated / point load magnitude (typically in kN) +- a = location of concentrated / point load from left end +- b = location of concentrated / point load from right end of +- EI = bending stiffness (typically in kN*m^2) +- EA = axial stiffness (typically in kN*m/m) +""" + + +def describe_analytical_validation_tests(): + # Analytical validation tests, ensuring correct results for full FEA runs + + def context_simply_supported_beam_validation(): + # Simply-supported beam with UDL validation + + w = 1 + l = 2 + EI = 10000 + EA = 1000 + + system = SystemElements(EI=EI, EA=EA, mesh=10000) + system.add_element([[0, 0], [l, 0]]) + system.add_support_hinged([1, 2]) + system.q_load(w, element_id=1) + system.solve() + + def it_results_in_correct_moment_shear(): + assert system.get_element_results(1)["Mmax"] == approx(w * l**2 / 8) + assert system.get_element_results(1)["Qmax"] == approx(w * l / 2) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(w * l / 2) + assert system.get_node_results_system(2)["Fy"] == approx(w * l / 2) + + def it_results_in_correct_deflections(): + assert system.get_element_results(1)["wtotmax"] == approx( + -5 * w * l**4 / (384 * EI) + ) + + def context_simply_supported_two_point_loads(): + # Validation tests of results, based upon analytical equations + + p = 80 + l = 5 + a = l / 3 + EI = 14000 + + system = SystemElements(EI=EI, mesh=10000) + system.add_element([[0, 0], [a, 0]]) + system.add_element([[a, 0], [2 * a, 0]]) + system.add_element([[2 * a, 0], [l, 0]]) + system.add_support_hinged([1, 4]) + system.point_load(node_id=2, Fy=p) + system.point_load(node_id=3, Fy=p) + system.solve() + + def it_results_in_correct_moment_shear(): + assert system.get_element_results(2)["Mmax"] == approx(p * a) + assert system.get_element_results(1)["Qmax"] == approx(p) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(p) + assert system.get_node_results_system(4)["Fy"] == approx(p) + + def it_results_in_correct_deflections(): + assert system.get_element_results(2)["wtotmax"] == approx( + -((p * a) / (24 * EI)) * (3 * (l**2) - 4 * (a**2)) + ) + + def context_simply_supported_beam_point_load_validation(): + # Simply-supported beam with point load at center validation + + w = 1 + l = 2 + EI = 10000 + EA = 1000 + p = 1 + + system = SystemElements(EI=EI, EA=EA, mesh=10000) + system.add_element([[0, 0], [l / 2, 0]]) + system.add_element([[l / 2, 0], [l, 0]]) + system.add_support_hinged([1, 3]) + system.point_load(2, Fx=0, Fy=p, rotation=0) + system.solve() + + def it_results_in_correct_moment_shear(): + assert system.get_element_results(1)["Mmax"] == approx(p * l / 4) + assert system.get_element_results(1)["Qmax"] == approx(p / 2) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(p / 2) + assert system.get_node_results_system(3)["Fy"] == approx(p / 2) + + def it_results_in_correct_deflections(): + assert system.get_node_results_system(2)["uy"] == approx( + -p * l**3 / (48 * EI) + ) + + def context_fixed_ends_beam_point_load_validation(): + # Beam fixed at both ends with concentrated load at center + + p = 200 + l = 8 + x = 3 + EI = 23000 + + system = SystemElements(EI=EI, mesh=9000) + system.add_element([[0, 0], [x, 0]]) + system.add_element([[x, 0], [l / 2, 0]]) + system.add_element([[l / 2, 0], [l, 0]]) + system.add_support_fixed([1, 4]) + system.point_load(3, Fx=0, Fy=200, rotation=0) + system.solve() + + def it_results_in_correct_moment_shear(): + assert system.get_element_results(2)["Mmin"] == approx(p / 8 * (4 * x - l)) + assert system.get_element_results(2)["Qmax"] == approx(p / 2) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(p / 2) + assert system.get_node_results_system(4)["Fy"] == approx(p / 2) + + def it_results_in_correct_deflections(): + assert system.get_node_results_system(2)["uy"] == approx( + -p * x**2 / (48 * EI) * (3 * l - 4 * x) + ) + + def context_3_span_continuous_beam_2_UDL_loads_validation(): + # Continuous Beam spanning over three supports with two UDL in the outer spans + + w = 70 + l = 5 + EI = 15000 + + system = SystemElements(EI=EI, mesh=20000) + system.add_element([[0, 0], [l, 0]]) + system.add_element([[l, 0], [2 * l, 0]]) + system.add_element([[2 * l, 0], [3 * l, 0]]) + system.add_support_hinged([1, 2, 3, 4]) + system.q_load(w, element_id=1) + system.q_load(w, element_id=3) + system.solve() + + def it_results_in_correct_moment_shear(): + assert system.get_element_results(1)["Mmax"] == approx(0.10125 * w * l**2) + assert system.get_element_results(2)["Mmax"] == approx(-0.050 * w * l**2) + assert system.get_element_results(1)["Qmin"] == approx(-0.55 * w * l) + assert system.get_element_results(2)["Qmax"] == approx(0) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(0.45 * w * l) + assert system.get_node_results_system(3)["Fy"] == approx(0.55 * w * l) + + def it_results_in_correct_deflections(): + assert system.get_element_results(1)["wtotmax"] == approx( + -0.009917469 * w * l**4 / EI + ) + + def it_results_in_correct_deflections(): + assert system.get_node_results_system(2)["uy"] == approx( + -p * l**3 / (48 * EI) + ) + + def context_fixed1end_simplySupported_UDL_validation(): + # beam fixed at one end and simply supported at the other with UDL + + EA = 3420000 # KN.m/m + EI = 83100 # KN.m^2 + w = 1 # KN/m + l = 2 # m + + system = SystemElements(EA=EA, EI=EI) + system.add_element([[0, 0], [l, 0]]) + system.add_support_hinged(1) + system.add_support_fixed(2) + system.q_load(w, element_id=1) + system.solve() + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(3 * w * l / 8) + assert system.get_node_results_system(2)["Fy"] == approx(5 * w * l / 8) + assert system.get_node_results_system(2)["Tz"] == approx(-w * (l**2) / 8) + + def it_results_in_correct_deflections(): + assert system.get_element_results(1)["wtotmax"] == approx( + -w * (l**4) / (185 * EI), rel=1e-3 + ) + + def context_fixed1end_simplySupported_pointLoad_validation(): + # beam fixed at one end and simply supported on other with point load at the middle + + EA = 3420000 # KN.m/m + EI = 83100 # KN.m^2 + p = 1 # KN + l = 2 # m + + system = SystemElements(EA=EA, EI=EI, mesh=10000) + system.add_element([[0, 0], [l * (1 / 5) ** 0.5, 0]]) + system.add_element([[l * (1 / 5) ** 0.5, 0], [l / 2, 0]]) + system.add_element([[l / 2, 0], [l, 0]]) + system.add_support_hinged(1) + system.add_support_fixed(4) + system.point_load(3, Fx=0, Fy=p, rotation=0) + system.solve() + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(5 * p / 16) + assert system.get_node_results_system(4)["Fy"] == approx(11 * p / 16) + assert system.get_node_results_system(4)["Tz"] == approx(-3 * p * l / 16) + + def it_results_in_correct_deflections(): + assert system.get_node_results_system(2)["uy"] == approx( + -p * (l**3) / (48 * EI * 5**0.5) + ) + + def context_beam_fixed_on_both_ends_UDL(): + # beam with fixed supports at both ends and UDL + + EA = 3420000 # KN.m/m + EI = 83100 # KN.m^2 + w = 1 # KN/m + l = 2 # m + + system = SystemElements(EA=EA, EI=EI, mesh=2000) + system.add_element([[0, 0], [l, 0]]) + system.add_support_fixed([1, 2]) + system.q_load(w, 1) + system.solve() + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(w * l / 2) + assert system.get_node_results_system(2)["Fy"] == approx(w * l / 2) + assert system.get_node_results_system(1)["Tz"] == approx(w * l**2 / 12) + assert system.get_node_results_system(2)["Tz"] == approx(-w * l**2 / 12) + + def it_results_in_correct_deflections(): + assert system.get_element_results(1)["wtotmax"] == approx( + -w * l**4 / (384 * EI) + ) + + def context_cantilever_UDL_validation(): + # Cantilever beam with UDL validation + + w = 10 + l = 3 + EI = 10000 + EA = 1000 + + system = SystemElements(EI=EI, EA=EA, mesh=100) + system.add_element([[0, 0], [l, 0]]) + system.add_support_fixed([2]) + system.q_load(w, element_id=1) + system.solve() + + def it_results_in_correct_moment_shear(): + assert system.get_element_results(1)["Mmin"] == approx(-w * l**2 / 2) + assert system.get_element_results(1)["Qmin"] == approx(-w * l) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(2)["Fy"] == approx(w * l) + + def it_results_in_correct_deflections(): + assert system.get_node_results_system(1)["uy"] == approx( + -w * l**4 / (8 * EI) + ) + + def context_remove_element(): + # Removing an element from a propped beam + + system = SystemElements() + system.add_element([[0, 0], [10, 0]]) + system.add_element([[10, 0], [15, 0]]) + system.add_support_hinged(1) + system.add_support_hinged(2) + system.q_load(q=-1, element_id=1) + system.q_load(q=-1, element_id=2) + system.point_load(node_id=3, Fy=-10) + system.remove_element(2) + system.solve() + + def it_removes_element(): + assert len(system.element_map) == 1 + assert not (2 in system.loads_q) + + def it_removes_orphaned_node(): + assert len(system.node_map) == 2 + assert not (3 in system.loads_point) + + def it_results_in_correct_reactions(): + assert system.get_node_results_system(1)["Fy"] == approx(-5) + assert system.get_node_results_system(2)["Fy"] == approx(-5) diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 2a4254e7..d753523c 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -25,14 +25,10 @@ def describe_end_to_end_tests(): - @pspec_context("End-to-End Tests (i.e. original unittest tests)") - def describe(): - pass + # End-to-End Tests (i.e. original unittest tests) def context_example_1(): - @pspec_context("Example 1") - def describe(): - pass + # Example 1 system = SystemElements() system.add_element(location=[[0, 0], [3, 4]], EA=5e9, EI=8000) @@ -52,9 +48,7 @@ def it_results_in_correct_solution(): assert system.solve() == approx(sol) def context_example_2(): - @pspec_context("Example 2") - def describe(): - pass + # Example 2 system = SystemElements() system.add_truss_element(location=[[0, 0], [0, 5]], EA=5000) @@ -76,9 +70,7 @@ def it_results_in_correct_solution(): assert system.solve() == approx(sol) def context_example_3(): - @pspec_context("Example 3") - def describe(): - pass + # Example 3 system = SystemElements() system.add_element(location=[[0, 0], [0, 5]], EA=15000, EI=5000) @@ -105,9 +97,7 @@ def it_results_in_correct_node_3_displacements(): assert system.get_node_displacements(3)["phi_z"] == approx(0.0021605118130) def context_example_4(): - @pspec_context("Example 4") - def describe(): - pass + # Example 4 system = SystemElements() system.add_element(location=[[0, 0], [5, 0]], EA=5e9, EI=8000, spring={2: 0}) @@ -127,9 +117,7 @@ def it_results_in_correct_solution(): assert system.solve() == approx(sol) def context_example_5(): - @pspec_context("Example 5") - def describe(): - pass + # Example 5 system = SystemElements() system.add_element(location=[[0, 0], [5, 0]], EA=5e9, EI=8000) @@ -149,11 +137,7 @@ def it_results_in_correct_solution(): assert system.solve() == approx(sol) def context_example_6_fixed_hinge(): - @pspec_context( - "Example 6: Test the primary force vector when applying a q_load at a hinged element." - ) - def describe(): - pass + # Example 6: Test the primary force vector when applying a q_load at a hinged element. system = SystemElements() system.add_element([[0, 0], [7, 0]], spring={2: 0}) @@ -166,9 +150,7 @@ def it_results_in_correct_in_correct_moment_at_support(): assert system.get_node_results_system(1)["Tz"] == approx(-61.25, rel=1e-3) def context_example_7_rotational_spring(): - @pspec_context("Example 7: Test the rotational springs") - def describe(): - pass + # Example 7: Test the rotational springs def it_results_in_correct_solution(SS_7): sol = np.fromstring( @@ -180,9 +162,7 @@ def it_results_in_correct_solution(SS_7): assert np.allclose(SS_7.solve(), sol) def context_example_8_rotational_spring(): - @pspec_context("Example 8: Test the plastic hinges") - def describe(): - pass + # Example 8: Test the plastic hinges def it_results_in_correct_total_displacement(SS_8): SS_8.solve() @@ -193,9 +173,7 @@ def it_results_in_correct_total_displacement(SS_8): assert u4 == approx(106.45829880642854) def context_example_11(): - @pspec_context("Example 11") - def describe(): - pass + # Example 11 def it_results_in_correct_axial_loads(SS_11): SS_11.solve() @@ -204,11 +182,7 @@ def it_results_in_correct_axial_loads(SS_11): assert SS_11.get_element_results(1)["length"] == approx(5.3851647) def context_example_12(): - @pspec_context( - "Example 12: Moment loads, with system nodes having 0 moment loads" - ) - def describe(): - pass + # Example 12: Moment loads, with system nodes having 0 moment loads" def it_results_in_correct_moment_loads(SS_12): SS_12.solve() @@ -218,9 +192,7 @@ def it_results_in_correct_moment_loads(SS_12): assert SS_12.get_node_results_system(4)["Tz"] == approx(-6.66667) def context_example_13(): - @pspec_context("Example 13: X-axis loads, with system nodes having 0 Fx loads") - def describe(): - pass + # Example 13: X-axis loads, with system nodes having 0 Fx loads def it_results_in_correct_moment_loads(SS_13): SS_13.solve() @@ -230,9 +202,7 @@ def it_results_in_correct_moment_loads(SS_13): assert SS_13.get_node_results_system(4)["Fx"] == approx(-6.66667) def context_example_14(): - @pspec_context("Example 14: Tests dead load and parallel load on axis.") - def describe(): - pass + # Example 14: Tests dead load and parallel load on axis. def it_results_in_correct_axial_loads(SS_14): SS_14.solve() @@ -243,9 +213,7 @@ def it_results_in_correct_axial_loads(SS_14): assert SS_14.get_node_results_system(5)["Fx"] == approx(5.18545) def context_example_15(): - @pspec_context("Example 15: Tests dead load and parallel load on axis.") - def describe(): - pass + # Example 15: Tests dead load and parallel load on axis. def it_results_in_correct_axial_loads(SS_15): SS_15.solve() @@ -256,9 +224,7 @@ def it_results_in_correct_axial_loads(SS_15): assert SS_15.get_node_results_system(5)["Fx"] == approx(9.41394) def context_example_16(): - @pspec_context("Example 16: Tests parallel load on axis.") - def describe(): - pass + # Example 16: Tests parallel load on axis. def it_results_in_correct_axial_loads(SS_16): SS_16.solve() @@ -269,18 +235,14 @@ def it_results_in_correct_axial_loads(SS_16): assert SS_16.get_node_results_system(5)["Fx"] == approx(5.65685) def context_example_18(): - @pspec_context("Example 18: Buckling factor") - def describe(): - pass + # Example 18: Buckling factor def it_results_in_correct_buckling_factor(SS_18): SS_18.solve(geometrical_non_linear=True) assert SS_18.buckling_factor == approx(600) def context_example_19(): - @pspec_context("Example 19: Numerical displacement averaging") - def describe(): - pass + # Example 19: Numerical displacement averaging def it_results_in_correct_deflections(SS_19): SS_19.solve() @@ -289,9 +251,7 @@ def it_results_in_correct_deflections(SS_19): ) def context_example_20(): - @pspec_context("Example 20: Inserting a node") - def describe(): - pass + # Example 20: Inserting a node def it_successfully_inserts_node(SS_20): x, y = SS_20.show_structure(values_only=True) @@ -307,18 +267,14 @@ def it_retains_supports_and_loads(SS_20): assert SS_20.element_map[5].q_load == approx((2.205258, 3)) def context_find_node_id(): - @pspec_context("find_node_id() function using Example 8") - def describe(): - pass + # find_node_id() function using Example 8 def it_finds_the_node_ids(SS_8): assert SS_8.find_node_id([4, 4]) == 6 assert SS_8.find_node_id([3, -3]) is None def context_add_multiple_elements(): - @pspec_context("add_multiple_elements() function") - def describe(): - pass + # add_multiple_elements() function system = SystemElements() system.add_multiple_elements([[0, 0], [10, 10]], n=5) @@ -328,9 +284,7 @@ def it_adds_multiple_elements(): assert node_x_locations == [0, 2.0, 4.0, 6.0, 8.0, 10] def context_no_forces_assertion(): - @pspec_context("Assertion error when no forces are entered") - def describe(): - pass + # Assertion error when no forces are entered system = SystemElements() system.add_element([0, 10]) @@ -340,9 +294,7 @@ def it_raises_an_error_with_no_forces(): system.solve() def context_inclined_horizontal_rollers(): - @pspec_context("Inclined rollers are equal to horizontal rollers") - def describe(): - pass + # Inclined rollers are equal to horizontal rollers system = SystemElements() x = [0, 1, 2] @@ -368,9 +320,7 @@ def it_results_in_same_forces(): assert u1["Tz"] == approx(u2["Tz"]) def context_inclined_roller_reactions(): - @pspec_context("Inclined roller forces are calculated correctly") - def describe(): - pass + # Inclined roller forces are calculated correctly system = SystemElements() x = [0, 1, 2] @@ -386,9 +336,7 @@ def it_results_in_correct_reactions(): assert system.get_node_results_system(3)["Fy"] == approx(-50) def context_inclined_roller_qload(): - @pspec_context("Inclined rollers and q-loads work together") - def describe(): - pass + # Inclined rollers and q-loads work together system = SystemElements(EA=356000, EI=1330) system.add_element(location=[[0, 0], [10, 0]]) @@ -404,9 +352,7 @@ def it_results_in_correct_reactions_forces(): assert system.get_element_results(1)["Nmin"] == approx(-5) def context_deflection_averaging_complex(): - @pspec_context("Deflection averaging test using example 26") - def describe(): - pass + # Deflection averaging test using example 26 def it_results_in_correct_deflections(SS_26): SS_26.solve() @@ -415,9 +361,7 @@ def it_results_in_correct_deflections(SS_26): ) def context_single_hinges_in_trusses(): - @pspec_context("Reducing elements in trusses to single hinges only") - def describe(): - pass + # Reducing elements in trusses to single hinges only system = SystemElements(EA=68300, EI=128, mesh=50) system.add_element( @@ -457,12 +401,7 @@ def it_results_in_correct_reactions(): assert system.get_node_results_system(3)["Tz"] == approx(0) def context_multiple_elements_spacing(): - @pspec_context( - "Tests bug fix for ensuring even spacing of multiple elements " - + "regardless of any floating point roundoff" - ) - def describe(): - pass + # Tests bug fix for ensuring even spacing of multiple elements regardless of any floating point roundoff system = SystemElements(EI=5e3, EA=1e5) system.add_multiple_elements([[0, 0], [10, 0]], 100) @@ -474,9 +413,7 @@ def it_results_in_valid_calculation(): assert system.get_node_results_system(-1)["uy"] == approx(2 / 3) def context_vertical_spring(): - @pspec_context("Test addition of vertical spring supports") - def describe(): - pass + # Test addition of vertical spring supports system = SystemElements(mesh=250) system.add_element( @@ -491,9 +428,7 @@ def it_results_in_correct_nodal_displacement(): assert system.get_node_results_system(2)["uy"] == approx(0.1) def context_rotational_roller_support(): - @pspec_context("Test addition of roller supports with rotational restraint") - def describe(): - pass + # Test addition of roller supports with rotational restraint system = SystemElements() system.add_element(location=[(0, 0), (0, 1)]) @@ -512,9 +447,7 @@ def it_results_in_correct_reaction(): assert system.get_node_results_system(2)["Tz"] == approx(166.6667) def context_rotational_support(): - @pspec_context("Test addition of rotation-only supports") - def describe(): - pass + # Test addition of rotation-only supports system = SystemElements() system.add_element(location=[(0, 0), (1, 0)]) @@ -533,9 +466,7 @@ def it_results_in_correct_reaction(): assert system.get_node_results_system(2)["Tz"] == approx(-166.6667) def context_load_cases(): - @pspec_context("Test a trivial load case") - def describe(): - pass + # Test a trivial load case system = SystemElements() system.add_truss_element(location=[[0, 0], [1000, 0]]) @@ -554,9 +485,7 @@ def it_results_in_correct_reactions(): assert results["dead"].get_node_results_system(2)["Fx"] == approx(14) def context_perpendicular_trapezoidal_load(): - @pspec_context("Test a complex-loaded system with trapezoidal loads") - def describe(): - pass + # Test a complex-loaded system with trapezoidal loads system = SystemElements() system.add_element(location=[(0, 0), (1, 0)]) @@ -582,9 +511,7 @@ def it_results_in_correct_reactions(): assert system.get_node_results_system(2)["Tz"] == approx(-5.8625) def context_internal_hinge_symmetry(): - @pspec_context("Test bug fix for asymmetric results with internal hinges") - def describe(): - pass + # Test bug fix for asymmetric results with internal hinges system = SystemElements() system.add_element(location=[[0, 0], [5, 0]], spring={2: 0}) @@ -606,9 +533,7 @@ def it_results_in_symmetric_element_demands(): ) def context_q_and_q_perp_loads(): - @pspec_context("Test addition of simultaneous q and q_perp loads") - def describe(): - pass + # Test addition of simultaneous q and q_perp loads system = SystemElements() system.add_element([2, 2]) @@ -626,9 +551,7 @@ def it_results_in_correct_element_demands(): assert system.get_element_results(1)["Qmax"] == approx(2 * np.sqrt(2)) def context_parallel_trapezoidal_load(): - @pspec_context("Test additional of parallel trapezoidal loads") - def describe(): - pass + # Test additional of parallel trapezoidal loads system = SystemElements() system.add_element([0, 1]) @@ -647,12 +570,7 @@ def it_results_in_correct_reaction(): assert system.get_node_results_system(1)["Fy"] == approx(-1) def context_load_case_example(): - @pspec_context( - "Test documentation example of load cases from " - + "https://anastruct.readthedocs.io/en/latest/loadcases.html" - ) - def describe(): - pass + # Test documentation example of load cases from https://anastruct.readthedocs.io/en/latest/loadcases.html system = SystemElements() height = 10 @@ -732,315 +650,3 @@ def it_results_in_correct_combination_demands_reactions(): assert results["combination"].get_node_results_system(5)["Fy"] == approx( wind_Fy + cables_Fy ) - - -def describe_analytical_validation_tests(): - @pspec_context("Validation tests of results, based upon analytical equations") - def describe(): - pass - - def context_simply_supported_beam_validation(): - @pspec_context("Simply-supported beam with UDL validation") - def describe(): - pass - - w = 1 - l = 2 - EI = 10000 - EA = 1000 - - system = SystemElements(EI=EI, EA=EA, mesh=10000) - system.add_element([[0, 0], [l, 0]]) - system.add_support_hinged([1, 2]) - system.q_load(w, element_id=1) - system.solve() - - def it_results_in_correct_moment_shear(): - assert system.get_element_results(1)["Mmax"] == approx(w * l**2 / 8) - assert system.get_element_results(1)["Qmax"] == approx(w * l / 2) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(w * l / 2) - assert system.get_node_results_system(2)["Fy"] == approx(w * l / 2) - - def it_results_in_correct_deflections(): - assert system.get_element_results(1)["wtotmax"] == approx( - -5 * w * l**4 / (384 * EI) - ) - - def context_simply_supported_two_point_loads(): - @pspec_context("Validation tests of results, based upon analytical equations") - def describe(): - pass - - p = 80 - l = 5 - a = l / 3 - EI = 14000 - - system = SystemElements(EI=EI, mesh=10000) - system.add_element([[0, 0], [a, 0]]) - system.add_element([[a, 0], [2 * a, 0]]) - system.add_element([[2 * a, 0], [l, 0]]) - system.add_support_hinged([1, 4]) - system.point_load(node_id=2, Fy=p) - system.point_load(node_id=3, Fy=p) - system.solve() - - def it_results_in_correct_moment_shear(): - assert system.get_element_results(2)["Mmax"] == approx(p * a) - assert system.get_element_results(1)["Qmax"] == approx(p) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(p) - assert system.get_node_results_system(4)["Fy"] == approx(p) - - def it_results_in_correct_deflections(): - assert system.get_element_results(2)["wtotmax"] == approx( - -((p * a) / (24 * EI)) * (3 * (l**2) - 4 * (a**2)) - ) - - def context_simply_supported_beam_point_load_validation(): - @pspec_context("Simply-supported beam with point load at center validation") - def describe(): - pass - - w = 1 - l = 2 - EI = 10000 - EA = 1000 - p = 1 - - system = SystemElements(EI=EI, EA=EA, mesh=10000) - system.add_element([[0, 0], [l / 2, 0]]) - system.add_element([[l / 2, 0], [l, 0]]) - system.add_support_hinged([1, 3]) - system.point_load(2, Fx=0, Fy=p, rotation=0) - system.solve() - - def it_results_in_correct_moment_shear(): - assert system.get_element_results(1)["Mmax"] == approx(p * l / 4) - assert system.get_element_results(1)["Qmax"] == approx(p / 2) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(p / 2) - assert system.get_node_results_system(3)["Fy"] == approx(p / 2) - - def it_results_in_correct_deflections(): - assert system.get_node_results_system(2)["uy"] == approx( - -p * l**3 / (48 * EI) - ) - - def context_fixed_ends_beam_point_load_validation(): - @pspec_context("Beam fixed at both ends with concentrated load at center") - def describe(): - pass - - p = 200 - l = 8 - x = 3 - EI = 23000 - - system = SystemElements(EI=EI, mesh=9000) - system.add_element([[0, 0], [x, 0]]) - system.add_element([[x, 0], [l / 2, 0]]) - system.add_element([[l / 2, 0], [l, 0]]) - system.add_support_fixed([1, 4]) - system.point_load(3, Fx=0, Fy=200, rotation=0) - system.solve() - - def it_results_in_correct_moment_shear(): - assert system.get_element_results(2)["Mmin"] == approx(p / 8 * (4 * x - l)) - assert system.get_element_results(2)["Qmax"] == approx(p / 2) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(p / 2) - assert system.get_node_results_system(4)["Fy"] == approx(p / 2) - - def it_results_in_correct_deflections(): - assert system.get_node_results_system(2)["uy"] == approx( - -p * x**2 / (48 * EI) * (3 * l - 4 * x) - ) - - def context_3_span_continuous_beam_2_UDL_loads_validation(): - @pspec_context( - "Continuous Beam spanning over three supports with two UDL in the outer spans" - ) - def describe(): - pass - - w = 70 - l = 5 - EI = 15000 - - system = SystemElements(EI=EI, mesh=20000) - system.add_element([[0, 0], [l, 0]]) - system.add_element([[l, 0], [2 * l, 0]]) - system.add_element([[2 * l, 0], [3 * l, 0]]) - system.add_support_hinged([1, 2, 3, 4]) - system.q_load(w, element_id=1) - system.q_load(w, element_id=3) - system.solve() - - def it_results_in_correct_moment_shear(): - assert system.get_element_results(1)["Mmax"] == approx(0.10125 * w * l**2) - assert system.get_element_results(2)["Mmax"] == approx(-0.050 * w * l**2) - assert system.get_element_results(1)["Qmin"] == approx(-0.55 * w * l) - assert system.get_element_results(2)["Qmax"] == approx(0) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(0.45 * w * l) - assert system.get_node_results_system(3)["Fy"] == approx(0.55 * w * l) - - def it_results_in_correct_deflections(): - assert system.get_element_results(1)["wtotmax"] == approx( - -0.009917469 * w * l**4 / EI - ) - - def it_results_in_correct_deflections(): - assert system.get_node_results_system(2)["uy"] == approx( - -p * l**3 / (48 * EI) - ) - - def context_fixed1end_simplySupported_UDL_validation(): - @pspec_context( - "beam fixed at one end and simply supported at the other with UDL" - ) - def describe(): - pass - - EA = 3420000 # KN.m/m - EI = 83100 # KN.m^2 - w = 1 # KN/m - l = 2 # m - - system = SystemElements(EA=EA, EI=EI) - system.add_element([[0, 0], [l, 0]]) - system.add_support_hinged(1) - system.add_support_fixed(2) - system.q_load(w, element_id=1) - system.solve() - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(3 * w * l / 8) - assert system.get_node_results_system(2)["Fy"] == approx(5 * w * l / 8) - assert system.get_node_results_system(2)["Tz"] == approx(-w * (l**2) / 8) - - def it_results_in_correct_deflections(): - assert system.get_element_results(1)["wtotmax"] == approx( - -w * (l**4) / (185 * EI), rel=1e-3 - ) - - def context_fixed1end_simplySupported_pointLoad_validation(): - @pspec_context( - "beam fixed at one end and simply supported on other with point load at the middle" - ) - def describe(): - pass - - EA = 3420000 # KN.m/m - EI = 83100 # KN.m^2 - p = 1 # KN - l = 2 # m - - system = SystemElements(EA=EA, EI=EI, mesh=10000) - system.add_element([[0, 0], [l * (1 / 5) ** 0.5, 0]]) - system.add_element([[l * (1 / 5) ** 0.5, 0], [l / 2, 0]]) - system.add_element([[l / 2, 0], [l, 0]]) - system.add_support_hinged(1) - system.add_support_fixed(4) - system.point_load(3, Fx=0, Fy=p, rotation=0) - system.solve() - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(5 * p / 16) - assert system.get_node_results_system(4)["Fy"] == approx(11 * p / 16) - assert system.get_node_results_system(4)["Tz"] == approx(-3 * p * l / 16) - - def it_results_in_correct_deflections(): - assert system.get_node_results_system(2)["uy"] == approx( - -p * (l**3) / (48 * EI * 5**0.5) - ) - - def context_beam_fixed_on_both_ends_UDL(): - @pspec_context("beam with fixed supports at both ends and UDL") - def describe(): - pass - - EA = 3420000 # KN.m/m - EI = 83100 # KN.m^2 - w = 1 # KN/m - l = 2 # m - - system = SystemElements(EA=EA, EI=EI, mesh=2000) - system.add_element([[0, 0], [l, 0]]) - system.add_support_fixed([1, 2]) - system.q_load(w, 1) - system.solve() - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(w * l / 2) - assert system.get_node_results_system(2)["Fy"] == approx(w * l / 2) - assert system.get_node_results_system(1)["Tz"] == approx(w * l**2 / 12) - assert system.get_node_results_system(2)["Tz"] == approx(-w * l**2 / 12) - - def it_results_in_correct_deflections(): - assert system.get_element_results(1)["wtotmax"] == approx( - -w * l**4 / (384 * EI) - ) - - def context_cantilever_UDL_validation(): - @pspec_context("Cantilever beam with UDL validation") - def describe(): - pass - - w = 10 - l = 3 - EI = 10000 - EA = 1000 - - system = SystemElements(EI=EI, EA=EA, mesh=100) - system.add_element([[0, 0], [l, 0]]) - system.add_support_fixed([2]) - system.q_load(w, element_id=1) - system.solve() - - def it_results_in_correct_moment_shear(): - assert system.get_element_results(1)["Mmin"] == approx(-w * l**2 / 2) - assert system.get_element_results(1)["Qmin"] == approx(-w * l) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(2)["Fy"] == approx(w * l) - - def it_results_in_correct_deflections(): - assert system.get_node_results_system(1)["uy"] == approx( - -w * l**4 / (8 * EI) - ) - - def context_remove_element(): - @pspec_context("Removing an element from a propped beam") - def describe(): - pass - - system = SystemElements() - system.add_element([[0, 0], [10, 0]]) - system.add_element([[10, 0], [15, 0]]) - system.add_support_hinged(1) - system.add_support_hinged(2) - system.q_load(q=-1, element_id=1) - system.q_load(q=-1, element_id=2) - system.point_load(node_id=3, Fy=-10) - system.remove_element(2) - system.solve() - - def it_removes_element(): - assert len(system.element_map) == 1 - assert not (2 in system.loads_q) - - def it_removes_orphaned_node(): - assert len(system.node_map) == 2 - assert not (3 in system.loads_point) - - def it_results_in_correct_reactions(): - assert system.get_node_results_system(1)["Fy"] == approx(-5) - assert system.get_node_results_system(2)["Fy"] == approx(-5) diff --git a/tests/test_plotter.py b/tests/test_plotter.py index e14d2906..7c14a00b 100644 --- a/tests/test_plotter.py +++ b/tests/test_plotter.py @@ -6,7 +6,7 @@ class SimpleTest(unittest.TestCase): - show = True + show = False def test_example_1(self): system = se.SystemElements()