pyfebio 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyfebio might be problematic. Click here for more details.
- pyfebio/__init__.py +45 -0
- pyfebio/_types.py +95 -0
- pyfebio/boundary.py +119 -0
- pyfebio/constraints.py +41 -0
- pyfebio/contact.py +172 -0
- pyfebio/control.py +73 -0
- pyfebio/discrete.py +40 -0
- pyfebio/globals.py +12 -0
- pyfebio/include.py +5 -0
- pyfebio/initial.py +27 -0
- pyfebio/loaddata.py +51 -0
- pyfebio/loads.py +55 -0
- pyfebio/material.py +1191 -0
- pyfebio/mesh.py +354 -0
- pyfebio/meshadaptor.py +159 -0
- pyfebio/meshdata.py +52 -0
- pyfebio/meshdomains.py +65 -0
- pyfebio/model.py +144 -0
- pyfebio/module.py +14 -0
- pyfebio/output.py +298 -0
- pyfebio/py.typed +0 -0
- pyfebio/rigid.py +275 -0
- pyfebio/step.py +28 -0
- pyfebio-0.1.0.dist-info/METADATA +336 -0
- pyfebio-0.1.0.dist-info/RECORD +26 -0
- pyfebio-0.1.0.dist-info/WHEEL +4 -0
pyfebio/rigid.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
4
|
+
|
|
5
|
+
from ._types import (
|
|
6
|
+
StringFloatVec3,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Value(BaseXmlModel, validate_assignment=True):
|
|
11
|
+
lc: int = attr()
|
|
12
|
+
text: float = 1.0
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RigidFixed(BaseXmlModel, tag="rigid_bc", validate_assignment=True):
|
|
16
|
+
""" """
|
|
17
|
+
|
|
18
|
+
type: Literal["rigid_fixed"] = attr(default="rigid_fixed", frozen=True)
|
|
19
|
+
rb: str = element()
|
|
20
|
+
Rx_dof: Literal[0, 1] = element(default=0)
|
|
21
|
+
Ry_dof: Literal[0, 1] = element(default=0)
|
|
22
|
+
Rz_dof: Literal[0, 1] = element(default=0)
|
|
23
|
+
Ru_dof: Literal[0, 1] = element(default=0)
|
|
24
|
+
Rv_dof: Literal[0, 1] = element(default=0)
|
|
25
|
+
Rw_dof: Literal[0, 1] = element(default=0)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class RigidPrescribed(BaseXmlModel, tag="rigid_bc", validate_assignment=True):
|
|
29
|
+
type: Literal["rigid_displacement", "rigid_rotation"] = attr(default="rigid_displacement", frozen=True)
|
|
30
|
+
rb: str = element()
|
|
31
|
+
dof: Literal["x", "y", "z", "Ru", "Rv", "Rw"] = element()
|
|
32
|
+
relative: Literal[0, 1] = element(default=0)
|
|
33
|
+
value: Value = element()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class RigidBodyRotationVector(BaseXmlModel, tag="rigid_bc", validate_assignment=True):
|
|
37
|
+
class X(BaseXmlModel, tag="vx", validate_assignment=True):
|
|
38
|
+
lc: int = attr()
|
|
39
|
+
text: float = 0.0
|
|
40
|
+
|
|
41
|
+
class Y(BaseXmlModel, tag="vy", validate_assignment=True):
|
|
42
|
+
lc: int = attr()
|
|
43
|
+
text: float = 0.0
|
|
44
|
+
|
|
45
|
+
class Z(BaseXmlModel, tag="vz", validate_assignment=True):
|
|
46
|
+
lc: int = attr()
|
|
47
|
+
text: float = 0.0
|
|
48
|
+
|
|
49
|
+
type: Literal["rigid_rotation_vector"] = attr(default="rigid_rotation_vector", frozen=True)
|
|
50
|
+
rb: str = element()
|
|
51
|
+
vx: X = element()
|
|
52
|
+
vy: Y = element()
|
|
53
|
+
vz: Z = element()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class RigidBodyEulerAngle(BaseXmlModel, tag="rigid_bc", validate_assignment=True):
|
|
57
|
+
class X(BaseXmlModel, tag="Ex", validate_assignment=True):
|
|
58
|
+
lc: int = attr()
|
|
59
|
+
text: float = 0.0
|
|
60
|
+
|
|
61
|
+
class Y(BaseXmlModel, tag="Ey", validate_assignment=True):
|
|
62
|
+
lc: int = attr()
|
|
63
|
+
text: float = 0.0
|
|
64
|
+
|
|
65
|
+
class Z(BaseXmlModel, tag="Ez", validate_assignment=True):
|
|
66
|
+
lc: int = attr()
|
|
67
|
+
text: float = 0.0
|
|
68
|
+
|
|
69
|
+
type: Literal["rigid_euler_vector"] = attr(default="rigid_euler_vector", frozen=True)
|
|
70
|
+
rb: str = element()
|
|
71
|
+
Ex: X = element()
|
|
72
|
+
Ey: Y = element()
|
|
73
|
+
Ez: Z = element()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class RigidForceLoad(BaseXmlModel, tag="rigid_load", validate_assignment=True):
|
|
77
|
+
type: Literal["rigid_force"] = attr(default="rigid_force", frozen=True)
|
|
78
|
+
rb: str = element()
|
|
79
|
+
dof: Literal["Rx", "Ry", "Rz"] = element()
|
|
80
|
+
relative: Literal[0, 1] = element(default=0)
|
|
81
|
+
load_type: Literal[0, 1, 2] = element(default=1)
|
|
82
|
+
value: Value = element()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class RigidFollowerForceLoad(BaseXmlModel, tag="rigid_load", validate_assignment=True):
|
|
86
|
+
type: Literal["rigid_follower_force"] = attr(default="rigid_follower_force", frozen=True)
|
|
87
|
+
rb: str = element()
|
|
88
|
+
insertion: StringFloatVec3 = element()
|
|
89
|
+
relative: Literal[0, 1] = element(default=0)
|
|
90
|
+
force: StringFloatVec3 = element()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class RigidMomentLoad(BaseXmlModel, tag="rigid_load", validate_assignment=True):
|
|
94
|
+
type: Literal["rigid_moment"] = attr(default="rigid_moment", frozen=True)
|
|
95
|
+
rb: str = element()
|
|
96
|
+
dof: Literal["Ru", "Rv", "Rw"] = element()
|
|
97
|
+
relative: Literal[0, 1] = element(default=0)
|
|
98
|
+
value: Value = element()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class RigidFollowerMomentLoad(BaseXmlModel, tag="rigid_load", validate_assignment=True):
|
|
102
|
+
type: Literal["rigid_follower_moment"] = attr(default="rigid_follower_moment", frozen=True)
|
|
103
|
+
rb: str = element()
|
|
104
|
+
relative: Literal[0, 1] = element(default=0)
|
|
105
|
+
moment: StringFloatVec3 = element()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class RigidCableLoad(BaseXmlModel, tag="rigid_load", validate_assignment=True):
|
|
109
|
+
class CablePoint(BaseXmlModel, tag="rigid_cable_point", validate_assignment=True):
|
|
110
|
+
rigid_body_id: str = element()
|
|
111
|
+
position: StringFloatVec3 = element()
|
|
112
|
+
|
|
113
|
+
type: Literal["rigid_cable"] = attr(default="rigid_cable", frozen=True)
|
|
114
|
+
force_direction: StringFloatVec3 = element()
|
|
115
|
+
relative: Literal[0, 1] = element(default=1)
|
|
116
|
+
force: Value = element()
|
|
117
|
+
rigid_cable_point: list[CablePoint] = element(default=[])
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class RigidConnector(
|
|
121
|
+
BaseXmlModel,
|
|
122
|
+
tag="rigid_connector",
|
|
123
|
+
validate_assignment=True,
|
|
124
|
+
):
|
|
125
|
+
""" """
|
|
126
|
+
|
|
127
|
+
name: str = attr()
|
|
128
|
+
body_a: str = element()
|
|
129
|
+
body_b: str = element()
|
|
130
|
+
tolerance: float = element(default=0.1)
|
|
131
|
+
minaug: int = element(default=0)
|
|
132
|
+
maxaug: int = element(default=10)
|
|
133
|
+
gaptol: Literal[0] | float = element(default=0)
|
|
134
|
+
angtol: Literal[0] | float = element(default=0)
|
|
135
|
+
force_penalty: float = element(default=1)
|
|
136
|
+
moment_penalty: float = element(default=1)
|
|
137
|
+
auto_penalty: Literal[0, 1] = element(default=1)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Free(BaseXmlModel, validate_assignment=True):
|
|
141
|
+
text: Literal[0] = 0
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class RigidSphericalJoint(RigidConnector):
|
|
145
|
+
type: Literal["rigid spherical joint"] = attr(default="rigid spherical joint", frozen=True)
|
|
146
|
+
joint_origin: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
147
|
+
prescribed_rotation: Literal[0, 1] = element(default=0)
|
|
148
|
+
rotation_x: Value | Free = element(default=Free())
|
|
149
|
+
rotation_y: Value | Free = element(default=Free())
|
|
150
|
+
rotation_z: Value | Free = element(default=Free())
|
|
151
|
+
moment_x: Value | Free = element(default=Free())
|
|
152
|
+
moment_y: Value | Free = element(default=Free())
|
|
153
|
+
moment_z: Value | Free = element(default=Free())
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class RigidRevoluteJoint(RigidConnector):
|
|
157
|
+
class Free(BaseXmlModel):
|
|
158
|
+
text: Literal[0] = 0
|
|
159
|
+
|
|
160
|
+
type: Literal["rigid revolute joint"] = attr(default="rigid revolute joint", frozen=True)
|
|
161
|
+
laugon: Literal[0, 1] = element(default=0)
|
|
162
|
+
joint_origin: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
163
|
+
prescribed_rotation: Literal[0, 1] = element(default=0)
|
|
164
|
+
rotation_axis: StringFloatVec3 = element(default="0.0,0.0,1.0")
|
|
165
|
+
moment: Value | Free = element(default=Free())
|
|
166
|
+
rotation: Value | Free = element(default=Free())
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class RigidPrismaticJoint(RigidConnector):
|
|
170
|
+
type: Literal["rigid prismatic joint"] = attr(default="rigid prismatic joint", frozen=True)
|
|
171
|
+
joint_origin: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
172
|
+
prescribed_translation: Literal[0, 1] = element(default=0)
|
|
173
|
+
translation: Value | Free = element(default=Free())
|
|
174
|
+
force: Value | Free = element(default=Free())
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class RigidCylindricalJoint(RigidConnector):
|
|
178
|
+
type: Literal["rigid cylindrical joint"] = attr(default="rigid cylindrical joint", frozen=True)
|
|
179
|
+
laugon: Literal["PENALTY", "AUGLAG", "LAGMULT"] = element(default="PENALTY")
|
|
180
|
+
joint_origin: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
181
|
+
joint_axis: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
182
|
+
transverse_axis: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
183
|
+
prescribed_rotation: Literal[0, 1] = element(default=0)
|
|
184
|
+
prescribed_translation: Literal[0, 1] = element(default=0)
|
|
185
|
+
translation: Value | Free = element(default=Free())
|
|
186
|
+
force: Value | Free = element(default=Free())
|
|
187
|
+
rotation: Value | Free = element(default=Free())
|
|
188
|
+
moment: Value | Free = element(default=Free())
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class RigidPlanarJoint(RigidConnector):
|
|
192
|
+
type: Literal["rigid planar joint"] = attr(default="rigid planar joint", frozen=True)
|
|
193
|
+
joint_origin: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
194
|
+
rotation_axis: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
195
|
+
translation_axis_1: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
196
|
+
translation_axis_2: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
197
|
+
prescribed_rotation: Literal[0, 1] = element(default=0)
|
|
198
|
+
prescribed_translation_1: Literal[0, 1] = element(default=0)
|
|
199
|
+
prescribed_translation_2: Literal[0, 1] = element(default=0)
|
|
200
|
+
rotation: Value | Free = element(default=Free())
|
|
201
|
+
translation_1: Value | Free = element(default=Free())
|
|
202
|
+
translation_2: Value | Free = element(default=Free())
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class RigidLock(RigidConnector):
|
|
206
|
+
type: Literal["rigid lock"] = attr(default="rigid lock", frozen=True)
|
|
207
|
+
joint_origin: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
208
|
+
first_axis: StringFloatVec3 = element(default="1.0,0.0,0.0")
|
|
209
|
+
second_axis: StringFloatVec3 = element(default="0.0,1.0,0.0")
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class RigidSpring(RigidConnector):
|
|
213
|
+
type: Literal["rigid spring"] = attr(default="rigid spring", frozen=True)
|
|
214
|
+
k: float = element(default=1)
|
|
215
|
+
insertion_a: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
216
|
+
insertion_b: StringFloatVec3 = element(default="1.0,0.0,0.0")
|
|
217
|
+
free_length: Literal[0] | float = element(default=0)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class RigidDamper(RigidConnector):
|
|
221
|
+
type: Literal["rigid damper"] = attr(default="rigid damper", frozen=True)
|
|
222
|
+
c: float = element(default=1e-7)
|
|
223
|
+
insertion_a: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
224
|
+
insertion_b: StringFloatVec3 = element(default="1.0,0.0,0.0")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class RigidAngularDamper(RigidConnector):
|
|
228
|
+
type: Literal["rigid angular damper"] = attr(default="rigid angular damper", frozen=True)
|
|
229
|
+
c: float = element(default=1e-7)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class RigidContractileForce(RigidConnector):
|
|
233
|
+
type: Literal["rigid damper"] = attr(default="rigid damper", frozen=True)
|
|
234
|
+
insertion_a: StringFloatVec3 = element(default="0.0,0.0,0.0")
|
|
235
|
+
insertion_b: StringFloatVec3 = element(default="1.0,0.0,0.0")
|
|
236
|
+
f0: Value = element()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
RigidBCType = RigidFixed | RigidPrescribed | RigidBodyRotationVector | RigidBodyEulerAngle
|
|
240
|
+
|
|
241
|
+
RigidLoadType = RigidForceLoad | RigidFollowerForceLoad | RigidMomentLoad | RigidFollowerMomentLoad
|
|
242
|
+
|
|
243
|
+
RigidConnectorType = (
|
|
244
|
+
RigidSphericalJoint
|
|
245
|
+
| RigidRevoluteJoint
|
|
246
|
+
| RigidCylindricalJoint
|
|
247
|
+
| RigidPrismaticJoint
|
|
248
|
+
| RigidPlanarJoint
|
|
249
|
+
| RigidLock
|
|
250
|
+
| RigidSpring
|
|
251
|
+
| RigidDamper
|
|
252
|
+
| RigidAngularDamper
|
|
253
|
+
| RigidContractileForce
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class Rigid(BaseXmlModel, tag="Rigid", validate_assignment=True):
|
|
258
|
+
all_rigid_bcs: list[RigidBCType] = element(default=[], tag="rigid_bc")
|
|
259
|
+
all_rigid_loads: list[RigidLoadType] = element(default=[], tag="rigid_load")
|
|
260
|
+
all_rigid_connectors: list[RigidConnectorType] = element(default=[], tag="rigid_connector")
|
|
261
|
+
|
|
262
|
+
def add_rigid_bc(
|
|
263
|
+
self,
|
|
264
|
+
new_rigid_bc: RigidBCType,
|
|
265
|
+
):
|
|
266
|
+
self.all_rigid_bcs.append(new_rigid_bc)
|
|
267
|
+
|
|
268
|
+
def add_rigid_load(
|
|
269
|
+
self,
|
|
270
|
+
new_rigid_load: RigidLoadType,
|
|
271
|
+
):
|
|
272
|
+
self.all_rigid_loads.append(new_rigid_load)
|
|
273
|
+
|
|
274
|
+
def add_rigid_connector(self, new_rigid_connector: RigidConnectorType):
|
|
275
|
+
self.all_rigid_connectors.append(new_rigid_connector)
|
pyfebio/step.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from pydantic_xml import BaseXmlModel, attr, element
|
|
2
|
+
|
|
3
|
+
from .boundary import Boundary
|
|
4
|
+
from .constraints import Constraints
|
|
5
|
+
from .contact import Contact
|
|
6
|
+
from .control import Control
|
|
7
|
+
from .initial import Initial
|
|
8
|
+
from .loads import Loads
|
|
9
|
+
from .rigid import Rigid
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class StepEntry(BaseXmlModel, validate_assignment=True):
|
|
13
|
+
id: int = attr()
|
|
14
|
+
name: str = attr(default="Step")
|
|
15
|
+
control: Control | None = element(default=None, tag="Control")
|
|
16
|
+
initial: Initial | None = element(default=None, tag="Initial")
|
|
17
|
+
boundary: Boundary | None = element(default=None, tag="Boundary")
|
|
18
|
+
loads: Loads | None = element(default=None, tag="Loads")
|
|
19
|
+
constraints: Constraints | None = element(default=None, tag="Constraints")
|
|
20
|
+
contact: Contact | None = element(default=None, tag="Contact")
|
|
21
|
+
rigid: Rigid | None = element(default=None, tag="Rigid")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Step(BaseXmlModel, validate_assignment=True):
|
|
25
|
+
all_steps: list[StepEntry] = element(default=[], tag="step")
|
|
26
|
+
|
|
27
|
+
def add_step(self, new_step: StepEntry):
|
|
28
|
+
self.all_steps.append(new_step)
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyfebio
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python API for the FEBio finite element solver.
|
|
5
|
+
Author: Scott Sibole
|
|
6
|
+
Author-email: Scott Sibole <scott.sibole@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Requires-Dist: lxml>=6.0.1
|
|
9
|
+
Requires-Dist: meshio[all]>=5.3.5
|
|
10
|
+
Requires-Dist: pydantic-xml>=2.17.3
|
|
11
|
+
Requires-Python: >=3.13
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
This is a Python package for generating FEBio input files. We rely heavily on pydantic and pydantic-xml
|
|
17
|
+
for type validation and XML serialization. Many of FEBio's features are covered, but not all.
|
|
18
|
+
|
|
19
|
+
## Getting Started
|
|
20
|
+
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Testing](#testing)
|
|
23
|
+
- [Example](#example)
|
|
24
|
+
- [Documentation](https://comporthobiomech.github.io/pyfebio/index.html)
|
|
25
|
+
- [Features](#features)
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
We will build PyPi packages later. For now, you can install from source:
|
|
30
|
+
|
|
31
|
+
Clone with https:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/CompOrthoBiomech/pyfebio.git
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or,
|
|
38
|
+
|
|
39
|
+
Clone with ssh:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone git@github.com:CompOrthoBiomech/pyfebio.git
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Using uv:**
|
|
46
|
+
|
|
47
|
+
Install uv from [here](https://docs.astral.sh/uv/getting-started/installation/)
|
|
48
|
+
|
|
49
|
+
In top-level repository directory:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv sync
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This will create a virtual environment and install the package.
|
|
56
|
+
|
|
57
|
+
**Using pip:**
|
|
58
|
+
|
|
59
|
+
In top-level repository directory:
|
|
60
|
+
|
|
61
|
+
Create a virtual environment:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
python -m venv .venv
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Activate the virtual environment:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
source .venv/bin/activate
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Install the package:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
If you want to run the tests, additionally install the dev group dependencies:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install . --group dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Testing
|
|
86
|
+
|
|
87
|
+
We rely on FEBio to check our generated models are valid. Therefore, you will need to have FEBio installed and available in your PATH.
|
|
88
|
+
|
|
89
|
+
To run all the tests, execute the following command:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd src
|
|
93
|
+
pytest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
For tests that depend on running finite element simulations, you can find them in the pytest tmp_path directory, which varies by operating system.
|
|
97
|
+
|
|
98
|
+
For the latest run:
|
|
99
|
+
|
|
100
|
+
on Linux,
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cd /tmp/pytest-of-[USER]/pytest-current/[TEST_FUNCTION_NAME]current
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Example
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
import pyfebio
|
|
110
|
+
|
|
111
|
+
# Instantiate a model tree with default values
|
|
112
|
+
# This contains empty mesh, material, loads, boundary, etc. sections
|
|
113
|
+
my_model = pyfebio.model.Model()
|
|
114
|
+
|
|
115
|
+
# Let's create a single hex8 element explicitly
|
|
116
|
+
# Normally, you would use the meshio functions to import
|
|
117
|
+
nodes_list = [
|
|
118
|
+
[0.0, 0.0, 0.0],
|
|
119
|
+
[1.0, 0.0, 0.0],
|
|
120
|
+
[1.0, 1.0, 0.0],
|
|
121
|
+
[0.0, 1.0, 0.0],
|
|
122
|
+
[0.0, 0.0, 1.0],
|
|
123
|
+
[1.0, 0.0, 1.0],
|
|
124
|
+
[1.0, 1.0, 1.0],
|
|
125
|
+
[0.0, 1.0, 1.0],
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
elements_list = [[1, 2, 3, 4, 5, 6, 7, 8]]
|
|
129
|
+
|
|
130
|
+
# Add Nodes to an pyfebio.Nodes object
|
|
131
|
+
nodes = pyfebio.mesh.Nodes(name="nodes")
|
|
132
|
+
for i, node in enumerate(nodes_list):
|
|
133
|
+
nodes.add_node(pyfebio.mesh.Node(id=i + 1, text=",".join(map(str, node))))
|
|
134
|
+
|
|
135
|
+
# Add Elements to an pyfebio.Elements object
|
|
136
|
+
elements = pyfebio.mesh.Elements(name="box", type="hex8")
|
|
137
|
+
for i, element in enumerate(elements_list):
|
|
138
|
+
elements.add_element(pyfebio.mesh.Hex8Element(id=i + 1, text=",".join(map(str, element))))
|
|
139
|
+
|
|
140
|
+
# Append nodes and elements to the model's mesh section
|
|
141
|
+
my_model.mesh.nodes.append(nodes)
|
|
142
|
+
my_model.mesh.elements.append(elements)
|
|
143
|
+
|
|
144
|
+
# Let's make a node set for top and bottom
|
|
145
|
+
bottom_nodes = [1, 2, 3, 4]
|
|
146
|
+
top_nodes = [5, 6, 7, 8]
|
|
147
|
+
top_node_set = pyfebio.mesh.NodeSet(name="top", text=",".join(map(str, top_nodes)))
|
|
148
|
+
bottom_node_set = pyfebio.mesh.NodeSet(name="bottom", text=",".join(map(str, bottom_nodes)))
|
|
149
|
+
|
|
150
|
+
# Append the node sets to the model's mesh section
|
|
151
|
+
my_model.mesh.node_sets.append(top_node_set)
|
|
152
|
+
my_model.mesh.node_sets.append(bottom_node_set)
|
|
153
|
+
|
|
154
|
+
# We need a material
|
|
155
|
+
# the use of pyfebio.material.MaterialParameter is our solution
|
|
156
|
+
# to handle mapped, math, or directly specified values
|
|
157
|
+
my_material = pyfebio.material.MooneyRivlin(
|
|
158
|
+
id=1,
|
|
159
|
+
name="cartilage",
|
|
160
|
+
c1=pyfebio.material.MaterialParameter(text=10.0),
|
|
161
|
+
c2=pyfebio.material.MaterialParameter(text=1.0),
|
|
162
|
+
k=pyfebio.material.MaterialParameter(text=1000.0),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Define a solid domain for the box to assign the material
|
|
166
|
+
solid_domain = pyfebio.meshdomains.SolidDomain(name="box", mat="cartilage")
|
|
167
|
+
|
|
168
|
+
# add the solid domain
|
|
169
|
+
my_model.mesh_domains.add_solid_domain(solid_domain)
|
|
170
|
+
|
|
171
|
+
# add the material
|
|
172
|
+
my_model.material.add_material(my_material)
|
|
173
|
+
|
|
174
|
+
# Fix the bottom nodes (1 means BC DoF is active)
|
|
175
|
+
fixed_bottom = pyfebio.boundary.BCZeroDisplacement(node_set="bottom",
|
|
176
|
+
x_dof=1,
|
|
177
|
+
y_dof=1,
|
|
178
|
+
z_dof=1)
|
|
179
|
+
|
|
180
|
+
# Displace the top nodes in z
|
|
181
|
+
# We need to create a boundary.Value object that references a load curve
|
|
182
|
+
displacement_value = pyfebio.boundary.Value(lc=1, text=-0.2)
|
|
183
|
+
move_top = pyfebio.boundary.BCPrescribedDisplacement(
|
|
184
|
+
node_set="top", dof="z", value=displacement_value
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Add boundary conditions
|
|
188
|
+
my_model.boundary.add_bc(fixed_bottom)
|
|
189
|
+
my_model.boundary.add_bc(move_top)
|
|
190
|
+
|
|
191
|
+
# Now, create the loadcurve 1 we referenced
|
|
192
|
+
curve_points = pyfebio.loaddata.CurvePoints(points=["0.0,0.0", "1.0,1.0"])
|
|
193
|
+
load_curve1 = pyfebio.loaddata.LoadCurve(id=1, points=curve_points)
|
|
194
|
+
# And, add it to model
|
|
195
|
+
my_model.load_data.add_load_curve(load_curve1)
|
|
196
|
+
|
|
197
|
+
# Finally, save the model to disk
|
|
198
|
+
my_model.save("my_model.feb")
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Run the model from the CLI (assuming febio4 is on your PATH):
|
|
202
|
+
|
|
203
|
+
```{bash}
|
|
204
|
+
febio4 -i my_model.feb
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+

|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
## Features
|
|
211
|
+
|
|
212
|
+
Brief overview, see module documentation for more details. Unchecked are not yet implemented.
|
|
213
|
+
|
|
214
|
+
:white_check_mark: Implemented and tested
|
|
215
|
+
|
|
216
|
+
:ballot_box_with_check: Implemented but untested
|
|
217
|
+
|
|
218
|
+
:x: Not yet implemented
|
|
219
|
+
|
|
220
|
+
- Control
|
|
221
|
+
- :white_check_mark: All control settings
|
|
222
|
+
- Mesh Section
|
|
223
|
+
- :white_check_mark: Nodes
|
|
224
|
+
- :white_check_mark: Solid Elements:
|
|
225
|
+
- tet4, tet10, hex8, hex20, hex27, penta6
|
|
226
|
+
- :ballot_box_with_check: Shell Elements:
|
|
227
|
+
- tri3, tri6, quad4, quad8, quad9, q4ans, q4eas
|
|
228
|
+
- :ballot_box_with_check: Beam Elements:
|
|
229
|
+
- line2, line3
|
|
230
|
+
- :white_check_mark: Node, Element, Surface Sets
|
|
231
|
+
- MeshDomain
|
|
232
|
+
- :white_check_mark: Solid Domain
|
|
233
|
+
- :ballot_box_with_check: Shell Domain
|
|
234
|
+
- :ballot_box_with_check: Beam Domain
|
|
235
|
+
- :ballot_box_with_check: Granular control for integration schemes, etc.
|
|
236
|
+
- MeshData Section
|
|
237
|
+
- :ballot_box_with_check: Node Data
|
|
238
|
+
- :ballot_box_with_check: Scalar
|
|
239
|
+
- :ballot_box_with_check: Vector3
|
|
240
|
+
- :ballot_box_with_check: Element Data
|
|
241
|
+
- :ballot_box_with_check: Scalar
|
|
242
|
+
- :ballot_box_with_check: Vector3
|
|
243
|
+
- :x: Surface Data
|
|
244
|
+
- :x: Scalar
|
|
245
|
+
- :x: Vector3
|
|
246
|
+
- MeshAdaptor
|
|
247
|
+
- :ballot_box_with_check: Erosion
|
|
248
|
+
- :white_check_mark: MMG3d Remeshing
|
|
249
|
+
- :white_check_mark: hex_refine
|
|
250
|
+
- :white_check_mark: hex_refine2d
|
|
251
|
+
- :ballot_box_with_check: Criteria
|
|
252
|
+
- :ballot_box_with_check: element selection
|
|
253
|
+
- :ballot_box_with_check: math
|
|
254
|
+
- :ballot_box_with_check: min-max filter
|
|
255
|
+
- :white_check_mark: relative error
|
|
256
|
+
- :white_check_mark: stress
|
|
257
|
+
- :ballot_box_with_check: contact gap
|
|
258
|
+
- :ballot_box_with_check: damage
|
|
259
|
+
- :ballot_box_with_check: max variable
|
|
260
|
+
- Material
|
|
261
|
+
- :white_check_mark: Most Unconstrained Formulation Materials
|
|
262
|
+
- :white_check_mark: Most Uncoupled Formulation Materials
|
|
263
|
+
- :ballot_box_with_check: Prestrain Material
|
|
264
|
+
- :ballot_box_with_check: Fiber models
|
|
265
|
+
- :white_check_mark: Material Axis
|
|
266
|
+
- :white_check_mark: Vector Definition
|
|
267
|
+
- :white_check_mark: Fiber Vector
|
|
268
|
+
- :ballot_box_with_check: Continuous Fiber Distributions
|
|
269
|
+
- :ballot_box_with_check: Integration Schemes
|
|
270
|
+
- :ballot_box_with_check: Element-wise, mapped, or math parameter defintion
|
|
271
|
+
- :white_check_mark: Biphasic Materials
|
|
272
|
+
- :white_check_mark: Viscoelastic Materials
|
|
273
|
+
- :x: Multiphasic Materials
|
|
274
|
+
- :x: Biphasic-solute Materials
|
|
275
|
+
- :x: Chemical Reactions
|
|
276
|
+
- :x: Active Contraction Materials
|
|
277
|
+
- :x: Damage Materials
|
|
278
|
+
- :x: First-order Homogenization
|
|
279
|
+
- Rigid
|
|
280
|
+
- :ballot_box_with_check: Fixed Displacement and Rotation
|
|
281
|
+
- :ballot_box_with_check: Prescribed Displacement and Rotation
|
|
282
|
+
- :ballot_box_with_check: Precribed Rotation about Vector
|
|
283
|
+
- :ballot_box_with_check: Prescribed Euler Rotation
|
|
284
|
+
- :ballot_box_with_check: All Connectors
|
|
285
|
+
- :ballot_box_with_check: Follower Loads
|
|
286
|
+
- Initial
|
|
287
|
+
- :ballot_box_with_check: Initial Velocity
|
|
288
|
+
- :ballot_box_with_check: Initial Pre-strain
|
|
289
|
+
- Loads
|
|
290
|
+
- :ballot_box_with_check: Nodal Loads
|
|
291
|
+
- :ballot_box_with_check: Traction Loads (surface)
|
|
292
|
+
- :ballot_box_with_check: Pressure Loads (surface)
|
|
293
|
+
- :ballot_box_with_check: Fluid Flux (surface)
|
|
294
|
+
- :ballot_box_with_check: Fluid Pressure (surface)
|
|
295
|
+
- LoadData
|
|
296
|
+
- :white_check_mark: Load Curves
|
|
297
|
+
- :balloit_box_with_check: All Options
|
|
298
|
+
- :ballot_box_with_check: PID Controllers
|
|
299
|
+
- :ballot_box_with_check: Math Controllers
|
|
300
|
+
- Boundary
|
|
301
|
+
- :white_check_mark: Fixed Displacement (solid)
|
|
302
|
+
- :white_check_mark: Prescribed Displacement (solid)
|
|
303
|
+
- :ballot_box_with_check: Fixed Displacement (shell)
|
|
304
|
+
- :ballot_box_with_check: Prescribed Displacement (shell)
|
|
305
|
+
- :ballot_box_with_check: Precribed Deformation Gradient
|
|
306
|
+
- :ballot_box_with_check: Displacement Along Normals
|
|
307
|
+
- :ballot_box_with_check: Fix to Rigid Body
|
|
308
|
+
- :white_check_mark: Rigid Node Set Deformation (rotation about axis)
|
|
309
|
+
- :white_check_mark: Zero Fluid Pressure
|
|
310
|
+
- :ballot_box_with_check: Prescribed Fluid Pressure
|
|
311
|
+
- Constraints
|
|
312
|
+
- :ballot_box_with_check: Symmetry Plane
|
|
313
|
+
- :ballot_box_with_check: Prestrain
|
|
314
|
+
- :ballot_box_with_check: In-Situ Stretch
|
|
315
|
+
- Contact
|
|
316
|
+
- :ballot_box_with_check: Sliding
|
|
317
|
+
- :ballot_box_with_check: Elastic
|
|
318
|
+
- :ballot_box_with_check: Facet-Facet
|
|
319
|
+
- :ballot_box_with_check: Node-Facet
|
|
320
|
+
- :ballot_box_with_check: Biphasic
|
|
321
|
+
- :ballot_box_with_check: Sliding2
|
|
322
|
+
- :ballot_box_with_check: Contact Potential Formulation
|
|
323
|
+
- :ballot_box_with_check: Tie
|
|
324
|
+
- :ballot_box_with_check: Elastic
|
|
325
|
+
- :ballot_box_with_check: Facet-Facet
|
|
326
|
+
- :ballot_box_with_check: Node-Facet
|
|
327
|
+
- :ballot_box_with_check: Biphasic
|
|
328
|
+
- Step
|
|
329
|
+
- :ballot_box_with_check: Multistep Analysis
|
|
330
|
+
- Output
|
|
331
|
+
- :ballot_box_with_check: Log File Configuration
|
|
332
|
+
- :ballot_box_with_check: Plot File Configuration
|
|
333
|
+
- :ballot_box_with_check: Node Variables
|
|
334
|
+
- :ballot_box_with_check: Element Variables
|
|
335
|
+
- :ballot_box_with_check: Rigid Body Variables
|
|
336
|
+
- :ballot_box_with_check: Rigid Connector Variables
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
pyfebio/__init__.py,sha256=t_4CsqooLVNUaCqvcb_joXCfRjvnMfrhDoo7wrVn6JQ,599
|
|
2
|
+
pyfebio/_types.py,sha256=dNn1A1IR8rVnbAVBE0rfP9jgT6ky0S8NA81ApNApPlY,2326
|
|
3
|
+
pyfebio/boundary.py,sha256=A266CEJrLnF-4UNZZMOlUhwGVdsNKrkjh2rxPmQARAg,3891
|
|
4
|
+
pyfebio/constraints.py,sha256=QHs76vSyOKtZhWy2GoZ8aW9b8VhQwZ1o85TT_dXbPWU,1626
|
|
5
|
+
pyfebio/contact.py,sha256=0FL_TcebZJu7J0GiDeStUcNPGoGZ3WeeUMOrg0HW8UY,6469
|
|
6
|
+
pyfebio/control.py,sha256=uf8sY2771qwEeMRYH_AZa99oh0IPpKtTYiKwaYsgUo8,3255
|
|
7
|
+
pyfebio/discrete.py,sha256=KXac8tldGSBw3bh9Amn80vP8Bb2s36W5uv52vpQnvbY,1404
|
|
8
|
+
pyfebio/globals.py,sha256=33L0YV9pE6huMixHHDYID6N9MrKNYZuoeL3588ZXYc0,389
|
|
9
|
+
pyfebio/include.py,sha256=kyXcwq3h7pJ842GF9KvCXTqHzQmG8aTxAhN-RgzSJBs,124
|
|
10
|
+
pyfebio/initial.py,sha256=krXfiaENs9-b9RhuMHdhqrU-23fbVK_rv9ivgo1zv3w,939
|
|
11
|
+
pyfebio/loaddata.py,sha256=V9M6nMjDnz5c2xPDldg5-k73JHVjNV8ntgcS4EihD4k,1735
|
|
12
|
+
pyfebio/loads.py,sha256=xZdYB9Xg_q56QR1-BBbK6UvnnJIvWEAT_OWuHhv3FTw,1929
|
|
13
|
+
pyfebio/material.py,sha256=nU9gMQCs7ueq1EfyMlXypPCqMAkeEKpwrrGydduGJlU,61139
|
|
14
|
+
pyfebio/mesh.py,sha256=PwSGz7EqJFBkZlhf8_o0MqmsBStXznOeQcVJAFlX43U,12220
|
|
15
|
+
pyfebio/meshadaptor.py,sha256=ok06o6DqngJUJz7OOqC4paPu0y1SAlPkWaSbnLMl6e4,6299
|
|
16
|
+
pyfebio/meshdata.py,sha256=6w0lV98fHt3-HNmcnma0v6ngrGr9Z8JTBaGk-Kvw-hU,1549
|
|
17
|
+
pyfebio/meshdomains.py,sha256=dZjOaiP5kfXy3Ym9AgSetZIKgFSf35GikmGvWOnrsIU,2125
|
|
18
|
+
pyfebio/model.py,sha256=iFPvKvb1f_OzEGUCP0c3OJp4SehenuAJAiLtvCQnjQI,5320
|
|
19
|
+
pyfebio/module.py,sha256=JIJkuou0fHqyBYq_x2UfsW7g0hhZeimZCqdR31z0nP8,374
|
|
20
|
+
pyfebio/output.py,sha256=C-veR4HnVDscdmw4dQH51a0q933w_uawh5hXIe8LAWo,7996
|
|
21
|
+
pyfebio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
pyfebio/rigid.py,sha256=fQSzyX5RdEiRDK0lOFr19ybnjWVkJ8UZkUXiHybR8f0,10359
|
|
23
|
+
pyfebio/step.py,sha256=NGGzajCfO3ZOCJ22y1z3sIrJHyjpMcJ-uSgIKMFxZKU,1053
|
|
24
|
+
pyfebio-0.1.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
25
|
+
pyfebio-0.1.0.dist-info/METADATA,sha256=ndWZwRs1fo3vCLJFyYisGSIMWVdtdWpn-aI7P_jysXg,10275
|
|
26
|
+
pyfebio-0.1.0.dist-info/RECORD,,
|