patme 0.4.4__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 patme might be problematic. Click here for more details.

Files changed (46) hide show
  1. patme/__init__.py +52 -0
  2. patme/buildtools/__init__.py +7 -0
  3. patme/buildtools/rce_releasecreator.py +336 -0
  4. patme/buildtools/release.py +26 -0
  5. patme/femtools/__init__.py +5 -0
  6. patme/femtools/abqmsgfilechecker.py +137 -0
  7. patme/femtools/fecall.py +1092 -0
  8. patme/geometry/__init__.py +0 -0
  9. patme/geometry/area.py +124 -0
  10. patme/geometry/coordinatesystem.py +635 -0
  11. patme/geometry/intersect.py +284 -0
  12. patme/geometry/line.py +183 -0
  13. patme/geometry/misc.py +420 -0
  14. patme/geometry/plane.py +464 -0
  15. patme/geometry/rotate.py +244 -0
  16. patme/geometry/scale.py +152 -0
  17. patme/geometry/shape2d.py +50 -0
  18. patme/geometry/transformations.py +1831 -0
  19. patme/geometry/translate.py +139 -0
  20. patme/mechanics/__init__.py +4 -0
  21. patme/mechanics/loads.py +435 -0
  22. patme/mechanics/material.py +1260 -0
  23. patme/service/__init__.py +7 -0
  24. patme/service/decorators.py +85 -0
  25. patme/service/duration.py +96 -0
  26. patme/service/exceptionhook.py +104 -0
  27. patme/service/exceptions.py +36 -0
  28. patme/service/io/__init__.py +3 -0
  29. patme/service/io/basewriter.py +122 -0
  30. patme/service/logger.py +375 -0
  31. patme/service/mathutils.py +108 -0
  32. patme/service/misc.py +71 -0
  33. patme/service/moveimports.py +217 -0
  34. patme/service/stringutils.py +419 -0
  35. patme/service/systemutils.py +290 -0
  36. patme/sshtools/__init__.py +3 -0
  37. patme/sshtools/cara.py +435 -0
  38. patme/sshtools/clustercaller.py +420 -0
  39. patme/sshtools/facluster.py +350 -0
  40. patme/sshtools/sshcall.py +168 -0
  41. patme-0.4.4.dist-info/LICENSE +21 -0
  42. patme-0.4.4.dist-info/LICENSES/MIT.txt +9 -0
  43. patme-0.4.4.dist-info/METADATA +168 -0
  44. patme-0.4.4.dist-info/RECORD +46 -0
  45. patme-0.4.4.dist-info/WHEEL +4 -0
  46. patme-0.4.4.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,464 @@
1
+ # Copyright (C) 2020 Deutsches Zentrum fuer Luft- und Raumfahrt(DLR, German Aerospace Center) <www.dlr.de>
2
+ # SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+ """
6
+ documentation
7
+ """
8
+ import numpy as np
9
+
10
+ from patme import epsilon
11
+ from patme.geometry.intersect import Intersection
12
+ from patme.geometry.line import Line
13
+ from patme.geometry.rotate import Rotation
14
+ from patme.geometry.translate import Translation
15
+ from patme.service.exceptions import GeometryError, ImproperParameterError, InternalError
16
+ from patme.service.logger import log
17
+
18
+
19
+ class Plane:
20
+ """this class represents the mathematical description of a plane.
21
+
22
+ It provides necessary methods for calculating intersection points and other stuff.
23
+ A positioning point and the plane normal vector is necessary to establish the plane.
24
+
25
+
26
+ >>> plane = Plane()
27
+ >>> plane = plane.generatePlane([3,0,0], planeNormalVector = [0,0,1])
28
+ >>> plane.planeNormalVector
29
+ Translation([0., 0., 1.])
30
+ >>> plane.planePositioningVector
31
+ Translation([3, 0, 0])
32
+ >>> plane.getProjectedPoints([[2,0,0]])
33
+ array([[2., 0., 0.]])
34
+ """
35
+
36
+ def __init__(self, *args, **kwargs):
37
+ """
38
+ :param refPlane: string, optional if a standard projection plane is to be used ('xy', 'xz' and 'yz' possible)
39
+ :param planeID: string, specifying the id of the projection plane
40
+
41
+ """
42
+ self._n = None
43
+ self._position = None
44
+ self._planeOrientationVector1 = None
45
+ self._planeOrientationVector2 = None
46
+
47
+ refPlane = kwargs.pop("refPlane", None)
48
+
49
+ if refPlane:
50
+
51
+ allowedRefPlanes = ["xy", "xz", "yz"]
52
+ if refPlane not in allowedRefPlanes:
53
+ raise ImproperParameterError(
54
+ f'Parameter "refPlane" is "{refPlane}" but must be one of {allowedRefPlanes}'
55
+ )
56
+
57
+ self.planePositioningVector = np.zeros(3)
58
+
59
+ baseVector = np.eye(3)
60
+ self._planeOrientationVector1, self._planeOrientationVector2 = (
61
+ baseVector["xyz".index(axis), :] for axis in refPlane
62
+ )
63
+
64
+ self.generatePlane(self._position, self._planeOrientationVector1, self._planeOrientationVector2)
65
+
66
+ self.planeID = kwargs.pop("planeID", None)
67
+
68
+ if not self.planeID and refPlane:
69
+ self.planeID = f"Plane_{refPlane}"
70
+
71
+ for key in kwargs:
72
+ if not hasattr(self, key):
73
+ log.warning(f'Setting unknown key "{key}" in class {self.__class__} with name "{str(self)}"')
74
+ setattr(self, key, kwargs[key])
75
+
76
+ def copy(self):
77
+ """doc"""
78
+ return Plane(
79
+ planeID=f"{self.planeID}_copy",
80
+ _planeOrientationVector1=self.planeOrientationVector1,
81
+ _planeOrientationVector2=self.planeOrientationVector2,
82
+ _position=self._position,
83
+ _n=self._n,
84
+ )
85
+
86
+ def to_occ(self):
87
+ """doc"""
88
+ try:
89
+ from OCC.gp import gp_Ax3, gp_Dir, gp_Pln, gp_Pnt
90
+ except ImportError:
91
+ from OCC.Core.gp import gp_Ax3, gp_Dir, gp_Pln, gp_Pnt
92
+
93
+ origPos = gp_Pnt(*self._position)
94
+ normal = gp_Dir(*self.planeNormalVector)
95
+ Vx = gp_Dir(*self.planeOrientationVector1)
96
+ ax = gp_Ax3(origPos, normal, Vx)
97
+ return gp_Pln(ax)
98
+
99
+ def getDistanceToPoint(self, point):
100
+ """
101
+ this function is intended to calculate the distance from this plane to the given point p
102
+ d(P,E)=abs(n*p-d)/abs(n) with E: n*x = n*a = d
103
+
104
+ >>> plane = Plane()
105
+ >>> plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
106
+ >>> plane.getDistanceToPoint([0,0,10])
107
+ 10.0
108
+ >>> plane = Plane()
109
+ >>> plane = plane.generatePlane([0,0,0], planeNormalVector = [1,1,1])
110
+ >>> '{:03.1f}'.format(plane.getDistanceToPoint([1,1,1])**2)
111
+ '3.0'
112
+
113
+ :param point: instance of type Translation(), specifying the point, from which the distance to the plane shall be calculated
114
+ """
115
+ distanceNominator = abs(
116
+ np.dot(point, self.planeNormalVector) - np.dot(self.planeNormalVector, self.planePositioningVector)
117
+ )
118
+ return distanceNominator / np.linalg.norm(self.planeNormalVector)
119
+
120
+ @staticmethod
121
+ def fromPointCloud(points):
122
+ from patme.geometry.misc import PCA
123
+
124
+ _, v = PCA(points)
125
+ point = np.mean(points, axis=0)
126
+ return Plane().generatePlane(point, planeNormalVector=v[:, 2])
127
+
128
+ def generatePlane(
129
+ self, positioningPoint=None, orientationPoint1=None, orientationPoint2=None, planeNormalVector=None
130
+ ):
131
+ """
132
+ :param positioningPoint: instance of type Translation(), specifying a point within the projection plane
133
+ :param orientationPoint1: instance of type Translation(), specifying an orientation vector within the projection plane
134
+ :param orientationPoint2: instance of type Translation(), specifying an orientation vector within the projection perpendicular to orientationPoint1
135
+ """
136
+
137
+ if positioningPoint is not None and orientationPoint1 is not None and orientationPoint2 is not None:
138
+ self.planePositioningVector = Translation(positioningPoint)
139
+ self._planeOrientationVector1 = np.asarray(orientationPoint1) - self.planePositioningVector
140
+ self._planeOrientationVector2 = np.asarray(orientationPoint2) - self.planePositioningVector
141
+
142
+ # Ebenennormalenvektor bestimmen
143
+ # n = planeOrientationVector1 x planeOrientationVector2
144
+ # n*(x-planePositionVector) = 0
145
+ self.planeNormalVector = np.cross(self._planeOrientationVector1, self._planeOrientationVector2)
146
+
147
+ elif positioningPoint is not None and planeNormalVector is not None:
148
+ self.planePositioningVector = Translation(positioningPoint)
149
+ self.planeNormalVector = planeNormalVector
150
+
151
+ self.setPlaneOrientationVectors()
152
+
153
+ else:
154
+ raise InternalError("At least one point for a proper plane definition is missing.")
155
+
156
+ self.normalizeVectors()
157
+
158
+ return self
159
+
160
+ def getIntersection(self, lines=None, areas=None):
161
+ """This method is intended to return the intersection of the provided input with itself.
162
+ Depending on the input this method returns an instance of Translation or an
163
+ instance of Line
164
+
165
+ >>> plane = Plane()
166
+ >>> plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
167
+ >>> plane.getIntersection(lines = [Line(Translation([0,0,0]),Translation([0,0,1]))])
168
+ Translation([0., 0., 0.])
169
+ """
170
+ if lines is None:
171
+ lines = []
172
+ if areas is None:
173
+ areas = []
174
+
175
+ if lines:
176
+ return Intersection.getIntersection(lines=lines, areas=[self])
177
+ elif areas:
178
+ areas.insert(0, self)
179
+ return Intersection.getIntersection(areas=areas)
180
+ else:
181
+ raise ImproperParameterError("No line or area specified for intersection.")
182
+
183
+ def getIntersectionPointOfVetor(self, vectorPoint, vectorOrienation):
184
+ """Calculates the intersection point of a vector with this plane. The vector must not be parallel to the plane
185
+
186
+ :return: Translation defining the intersection point
187
+ :raises GeometryError: in case vector is parallel to plane
188
+
189
+ >>> plane = Plane()
190
+ >>> plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
191
+ >>> plane.getIntersectionPointOfVetor([0,0,0],[0,0,1])
192
+ Translation([0., 0., 0.])
193
+ """
194
+ line = Line(Translation(vectorPoint), Translation(vectorPoint) + vectorOrienation)
195
+ result = Intersection.getIntersection(lines=[line], areas=[self])
196
+
197
+ if result is None:
198
+ raise GeometryError("Line is parallel to plane and not coincident")
199
+ if result is line:
200
+ raise GeometryError("Line is parallel and coincident to plane")
201
+
202
+ return Translation(result)
203
+
204
+ def getProjectedPoints(self, points=None, transformIntoPlaneCoordinates=False):
205
+ """This method is intended to provide the functionality of orthogonal projection of points and lines onto a plane.
206
+
207
+ :param points: list of points to be projected
208
+ :param transformIntoPlaneCoordinates: Flag, if the resulting points should be absolute or in the plane
209
+ coordinate system including the plane's rotation
210
+
211
+ >>> plane = Plane()
212
+ >>> plane = plane.generatePlane([0,0,1], planeNormalVector = [0,0,1])
213
+ >>> plane.getProjectedPoints([[1,0,3],[0,1,3]])
214
+ array([[1., 0., 1.],
215
+ [0., 1., 1.]])
216
+ >>> plane = plane.generatePlane([0,0,1], planeNormalVector = [0,0,1])
217
+ >>> plane.getProjectedPoints([[1,0,3],[0,1,3]], transformIntoPlaneCoordinates=True)
218
+ array([[1., 0., 0.],
219
+ [0., 1., 0.]])
220
+
221
+ .. figure:: ../../bilder/reference/IMG7254.PNG
222
+ :width: 250pt
223
+ :align: center
224
+
225
+ Common equation of plane:
226
+
227
+ .. math::
228
+ \\\\
229
+ \\vec{e} = \\vec{ap}+\\lambda\\cdot\\vec{rv_{1}}+\\mu\\cdot\\vec{rv_{1}}
230
+
231
+ Common equation of linear function:
232
+
233
+ .. math::
234
+ \\\\
235
+ \\vec{x_{g}} = \\vec{p}+\\omega\\cdot\\vec{rv_{g}}
236
+
237
+ Common equation of projection of the linear function:
238
+
239
+ .. math::
240
+ \\\\
241
+ \\vec{x_{s}} = \\vec{p_{s}}+\\omega\\cdot\\vec{rv_{gs}}
242
+
243
+ Common equations for supporting functions:
244
+
245
+ .. math::
246
+ \\\\
247
+ \\vec{x_{h1}} = \\vec{p}+\\sigma\\cdot\\vec{n},\\, with\\; \\vec{n}\\; the\\; normal\\; vector\\; of\\; \\vec{e}
248
+ \\\\
249
+ \\vec{x_{h2}} = \\vec{q}+\\eta\\cdot\\vec{n},\\, with\\; \\vec{n}\\; the\\; normal\\; vector\\; of\\; \\vec{e}
250
+
251
+ """
252
+ # Hilfsgeradeen aufstellen
253
+ # h1(omega) = functionPositionVector + omega*self.planeNormalVector
254
+
255
+ # Gleichungssystem loesen:
256
+ # Solve ``-sigma*n_1+lambda*rv1_1+mu*rv2_1 = p_1-ap_1``
257
+ # ``-sigma*n_2+lambda*rv1_2+mu*rv2_2 = p_2-ap_2``
258
+ # ``-sigma*n_3+lambda*rv1_3+mu*rv2_3 = p_3-ap_3``
259
+
260
+ # h1(omega) = E(alpha,beta)
261
+ if len(points) == 1:
262
+ pointsArray = np.array([points[0]])
263
+ else:
264
+ pointsArray = np.array(points, copy=True)
265
+
266
+ rechteSeiten = pointsArray - np.array(self.planePositioningVector)
267
+
268
+ koeffMat = np.array(
269
+ [-1 * self.planeNormalVector[:3], self._planeOrientationVector1[:3], self._planeOrientationVector2[:3]]
270
+ ).T
271
+
272
+ # [sigma, lambda, mu]
273
+ unknownParms = np.linalg.solve(koeffMat, rechteSeiten.T)
274
+
275
+ # evaluate supporting function to get intersection point
276
+ planeNormals = np.outer(self.planeNormalVector, np.ones(pointsArray.shape[0]))
277
+
278
+ newPoints = pointsArray + (unknownParms[0, :] * planeNormals).T
279
+
280
+ if transformIntoPlaneCoordinates:
281
+ newPoints -= self.planePositioningVector
282
+ unknownParms = np.linalg.lstsq(self.rotation, newPoints.T, rcond=None)[0]
283
+ newPoints = unknownParms.T
284
+
285
+ return newPoints
286
+
287
+ def setPlaneOrientationVectors(self):
288
+ """doc"""
289
+ # create a vector deviating a bit from normal vector
290
+ newVector = None
291
+ for translation in np.eye(3, 3):
292
+ newVector = self.planeNormalVector + translation
293
+ auxVector = np.cross(self.planeNormalVector, newVector)
294
+
295
+ # check whether new vector is linear independent from plane normal vector
296
+ vectorMatrix = np.array([self.planeNormalVector, newVector, auxVector])
297
+
298
+ if np.linalg.det(vectorMatrix.T) > epsilon:
299
+ # vectors are linear independent - no new vector has to be created
300
+ break
301
+
302
+ # calculate part of newVector parallel to plane normal vector
303
+ nParallelVec = (
304
+ np.dot(self.planeNormalVector, newVector)
305
+ / np.dot(self.planeNormalVector, self.planeNormalVector)
306
+ * self.planeNormalVector
307
+ )
308
+
309
+ # calculate first vector in plane
310
+ self._planeOrientationVector1 = Translation(newVector - nParallelVec)
311
+
312
+ # calculate second vector in plane
313
+ self._planeOrientationVector2 = Translation(np.cross(self.planeNormalVector, self._planeOrientationVector1))
314
+
315
+ self.planeNormalVector = Translation(np.cross(self._planeOrientationVector1, self._planeOrientationVector2))
316
+
317
+ def getNearestPointFromList(self, pointList):
318
+ """Returns the point of list pointList which is closest to the plane.
319
+
320
+ :param pointList: list of keypoints (or 3D coordinates)
321
+ :return: the point of pointList closest to the plane
322
+ """
323
+ distancesToPlane = np.array([self.getDistanceToPoint(np.array(point)) for point in pointList])
324
+ return pointList[np.argmin(distancesToPlane)]
325
+
326
+ @staticmethod
327
+ def fromTransformation(rotation, position):
328
+ """doc"""
329
+ refPos1 = position + rotation[:, 0] / np.linalg.norm(rotation[:, 0])
330
+ refPos2 = position + rotation[:, 1] / np.linalg.norm(rotation[:, 1])
331
+ return Plane().generatePlane(position, refPos1, refPos2)
332
+
333
+ def makeOrthogonal(self, adaptVectorNum=1):
334
+ """doc"""
335
+ # adapt orientation vector to get orthogonal vectors
336
+ if adaptVectorNum not in [1, 2]:
337
+ log.warning(
338
+ "Only [1,2] are valid numbers for parameter 'adaptVectorNum' in function Plane.makeOrthogonal. Set to 1"
339
+ )
340
+ adaptVectorNum = 1
341
+
342
+ if adaptVectorNum == 1:
343
+ self._planeOrientationVector1 = Translation(np.cross(self.planeOrientationVector2, self.planeNormalVector))
344
+ else:
345
+ self._planeOrientationVector2 = Translation(np.cross(self.planeNormalVector, self.planeOrientationVector1))
346
+
347
+ def normalizeVectors(self):
348
+ """doc"""
349
+ self.planeNormalVector /= np.linalg.norm(self.planeNormalVector)
350
+ self._planeOrientationVector1 /= np.linalg.norm(self._planeOrientationVector1)
351
+ self._planeOrientationVector2 /= np.linalg.norm(self._planeOrientationVector2)
352
+
353
+ def plot(self, axes=None):
354
+ """doc"""
355
+ import matplotlib.pyplot as plt
356
+
357
+ copyPlane = self.copy()
358
+ copyPlane.makeOrthogonal(2)
359
+
360
+ xx, yy = np.meshgrid(np.linspace(-2, 2, 21), np.linspace(-2, 2, 21))
361
+ allPoints = np.c_[xx.ravel(), yy.ravel()]
362
+
363
+ from scipy.spatial import Delaunay
364
+
365
+ tri = Delaunay(allPoints)
366
+
367
+ allPoints = np.c_[allPoints, np.zeros(allPoints.shape[0])]
368
+ newPoints = (self.rotation * allPoints.T).T + self.planePositioningVector
369
+
370
+ if not axes:
371
+ axes = plt.figure().gca(projection="3d")
372
+
373
+ axes.set_aspect("equal")
374
+ axes.plot_trisurf(
375
+ newPoints[:, 0], newPoints[:, 1], newPoints[:, 2], linewidth=0, triangles=tri.simplices, alpha=0.2
376
+ )
377
+
378
+ return axes
379
+
380
+ def switchAxes(self):
381
+ """doc"""
382
+ tmpVector1 = self.planeOrientationVector1
383
+ self._planeOrientationVector1 = np.copy(self.planeOrientationVector2)
384
+ self._planeOrientationVector2 = np.copy(tmpVector1)
385
+ self.planeNormalVector = np.cross(self._planeOrientationVector1, self._planeOrientationVector2)
386
+
387
+ def _hasOrthogonalBase(self):
388
+ """doc"""
389
+ dotProduct = self.planeOrientationVector1 @ self.planeOrientationVector2
390
+ norm = np.linalg.norm(self.planeOrientationVector1) * np.linalg.norm(self.planeOrientationVector2)
391
+ return abs(dotProduct / norm) < 1e-08
392
+
393
+ def _getRotation(self):
394
+ """doc"""
395
+ if not self.hasOrthogonalBase:
396
+ return None
397
+ else:
398
+ return Rotation(
399
+ np.array([self.planeOrientationVector1, self.planeOrientationVector2, self.planeNormalVector]).T
400
+ )
401
+
402
+ def __str__(self):
403
+ """doc"""
404
+ if self.planeID:
405
+ return self.planeID
406
+
407
+ return object.__str__(self)
408
+
409
+ def _getNormalVector(self):
410
+ """doc"""
411
+ return self._n
412
+
413
+ def _setNormalVector(self, normalVector):
414
+ """doc"""
415
+ self._n = Translation(normalVector / np.linalg.norm(normalVector))
416
+
417
+ def _getPositionVector(self):
418
+ """doc"""
419
+ return self._position
420
+
421
+ def _setPositionVector(self, positioningVector):
422
+ """doc"""
423
+ self._position = Translation(positioningVector)
424
+
425
+ def _getplaneOrientationVector1(self):
426
+ """doc"""
427
+ return self._planeOrientationVector1
428
+
429
+ def _getplaneOrientationVector2(self):
430
+ """doc"""
431
+ return self._planeOrientationVector2
432
+
433
+ planeNormalVector = property(fget=_getNormalVector, fset=_setNormalVector)
434
+ # normal vector of the plane
435
+ planeOrientationVector1 = property(fget=_getplaneOrientationVector1)
436
+ planeOrientationVector2 = property(fget=_getplaneOrientationVector2)
437
+ planePositioningVector = property(fget=_getPositionVector, fset=_setPositionVector)
438
+ hasOrthogonalBase = property(fget=_hasOrthogonalBase)
439
+ rotation = property(fget=_getRotation)
440
+
441
+
442
+ if __name__ == "__main__":
443
+
444
+ plane = Plane().generatePlane(np.array([1, 1, 1]), planeNormalVector=[2, 4, 3])
445
+ plane2 = plane.copy()
446
+ numPoints = 10
447
+ testPoints = np.random.rand(numPoints * 3).reshape((10, 3)) * 10
448
+ newPoint = plane.getProjectedPoints(testPoints, True)
449
+
450
+ #
451
+ # from mpl_toolkits.mplot3d import axes3d
452
+ # import matplotlib.pyplot as plt
453
+ #
454
+ # fig = plt.figure()
455
+ # ax = fig.gca(projection='3d')
456
+ # ax.scatter(xs = newPoint[:,0], ys = newPoint[:,1], zs = newPoint[:,2], marker="o", label='Data points')
457
+ # #plane.plot(ax)
458
+ # plt.show()
459
+ #
460
+ # #plane = plane.generatePlane([0,0,0], planeNormalVector = [0,0,1])
461
+ # #print(plane.getIntersection(lines = [Line(Translation([0,0,0]),Translation([0,0,1]))]))
462
+ #
463
+ # # import doctest
464
+ # # doctest.testmod()