femagtools 1.6.8__py3-none-any.whl → 1.7.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.
- femagtools/__init__.py +2 -2
- femagtools/bch.py +1 -1
- femagtools/dxfsl/area.py +334 -332
- femagtools/dxfsl/areabuilder.py +131 -10
- femagtools/dxfsl/conv.py +27 -9
- femagtools/dxfsl/converter.py +390 -125
- femagtools/dxfsl/corner.py +3 -0
- femagtools/dxfsl/femparser.py +1 -1
- femagtools/dxfsl/fslrenderer.py +290 -246
- femagtools/dxfsl/functions.py +4 -2
- femagtools/dxfsl/geom.py +1120 -886
- femagtools/dxfsl/journal.py +53 -22
- femagtools/dxfsl/machine.py +250 -74
- femagtools/dxfsl/plotrenderer.py +34 -3
- femagtools/dxfsl/shape.py +380 -103
- femagtools/dxfsl/symmetry.py +679 -110
- femagtools/femag.py +27 -2
- femagtools/forcedens.py +65 -40
- femagtools/fsl.py +71 -28
- femagtools/losscoeffs.py +46 -0
- femagtools/machine/effloss.py +8 -1
- femagtools/machine/im.py +3 -1
- femagtools/machine/pm.py +11 -7
- femagtools/machine/sizing.py +14 -11
- femagtools/machine/sm.py +114 -33
- femagtools/machine/utils.py +38 -34
- femagtools/model.py +12 -2
- femagtools/moo/population.py +1 -1
- femagtools/parstudy.py +17 -1
- femagtools/plot/__init__.py +1 -1
- femagtools/plot/char.py +24 -7
- femagtools/plot/forcedens.py +56 -29
- femagtools/plot/mcv.py +4 -1
- femagtools/plot/phasor.py +6 -1
- femagtools/poc.py +17 -10
- femagtools/templates/cogg_calc.mako +7 -1
- femagtools/templates/displ_stator_rotor.mako +33 -0
- femagtools/templates/fieldcalc.mako +10 -16
- femagtools/templates/pm_sym_f_cur.mako +1 -1
- femagtools/tks.py +3 -9
- {femagtools-1.6.8.dist-info → femagtools-1.7.0.dist-info}/LICENSE +1 -0
- {femagtools-1.6.8.dist-info → femagtools-1.7.0.dist-info}/METADATA +7 -4
- {femagtools-1.6.8.dist-info → femagtools-1.7.0.dist-info}/RECORD +50 -49
- tests/engines/__init__.py +0 -20
- tests/geom/__init__.py +0 -20
- tests/moo/__init__.py +0 -20
- tests/test_model.py +8 -1
- {femagtools-1.6.8.dist-info → femagtools-1.7.0.dist-info}/WHEEL +0 -0
- {femagtools-1.6.8.dist-info → femagtools-1.7.0.dist-info}/entry_points.txt +0 -0
- {femagtools-1.6.8.dist-info → femagtools-1.7.0.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/symmetry.py
CHANGED
@@ -16,6 +16,7 @@ from femagtools.dxfsl.functions import alpha_angle, positive_angle, is_same_angl
|
|
16
16
|
from femagtools.dxfsl.functions import min_angle, max_angle, gcd, point
|
17
17
|
from femagtools.dxfsl.functions import less_equal, less, points_are_close
|
18
18
|
from femagtools.dxfsl.functions import line_m, line_n, mirror_point
|
19
|
+
from femagtools.dxfsl.functions import part_of_circle, round_point
|
19
20
|
|
20
21
|
logger = logging.getLogger('femagtools.symmetry')
|
21
22
|
|
@@ -30,8 +31,8 @@ class Symmetry(object):
|
|
30
31
|
geom=None,
|
31
32
|
startangle=None,
|
32
33
|
endangle=None,
|
33
|
-
rtol=1e-
|
34
|
-
atol=1e-
|
34
|
+
rtol=1e-03,
|
35
|
+
atol=1e-02):
|
35
36
|
assert(geom is not None)
|
36
37
|
assert(startangle is not None)
|
37
38
|
assert(endangle is not None)
|
@@ -39,17 +40,23 @@ class Symmetry(object):
|
|
39
40
|
self.geom = geom
|
40
41
|
self.startangle = startangle
|
41
42
|
self.endangle = endangle
|
43
|
+
self.geom_part = part_of_circle(self.startangle, self.endangle, 1)
|
42
44
|
self.delta_check_count = 0
|
43
|
-
self.
|
45
|
+
self.delta_angle_corr = None
|
44
46
|
self.rtol = rtol
|
45
47
|
self.atol = atol
|
46
48
|
self.full = False
|
49
|
+
self.ag_radius = 0.0
|
47
50
|
if np.isclose(self.startangle, self.endangle):
|
48
51
|
self.alpha = 2.0*np.pi
|
49
52
|
self.full = True
|
50
53
|
else:
|
51
54
|
self.alpha = alpha_angle(self.startangle, self.endangle)
|
52
55
|
self.full = False
|
56
|
+
if geom.is_inner:
|
57
|
+
self.ag_radius = geom.max_radius
|
58
|
+
else:
|
59
|
+
self.ag_radius = geom.min_radius
|
53
60
|
logger.debug("Symmetry(alpha=%s, rtol=%s, atol=%s)", self.alpha, rtol, atol)
|
54
61
|
|
55
62
|
def __str__(self):
|
@@ -60,15 +67,33 @@ class Symmetry(object):
|
|
60
67
|
d1, h1, a1,
|
61
68
|
d2, h2, a2,
|
62
69
|
rtol=1e-03, atol=1e-03):
|
63
|
-
|
64
|
-
|
70
|
+
equal_d = np.isclose(d1, d2, rtol=rtol, atol=atol) # distance form c
|
71
|
+
equal_h = np.isclose(h1, h2, rtol=rtol, atol=atol) # height
|
72
|
+
equal_a = np.isclose(a1, a2, rtol=1e-4, atol=1e-2) # angle from c
|
73
|
+
if not equal_d:
|
74
|
+
logger.debug("equal_area: dist NOT close (%s/%s)", d1, d2)
|
75
|
+
if equal_h and equal_a: # but height and angle
|
76
|
+
if np.isclose(d1, d2, rtol=1e-2, atol=1.e-1):
|
77
|
+
logger.debug(" -- but with more tolerance")
|
78
|
+
return True
|
65
79
|
return False
|
66
|
-
if not
|
67
|
-
logger.debug("height NOT close (%s/%s)", h1, h2)
|
80
|
+
if not equal_h:
|
81
|
+
logger.debug("equal_area: height NOT close (%s/%s)", h1, h2)
|
82
|
+
if equal_d and equal_a: # but distance and angle
|
83
|
+
if np.isclose(h1, h2, rtol=1e-2, atol=1e-1) :
|
84
|
+
logger.debug(" -- but with more tolerance")
|
85
|
+
return True
|
68
86
|
return False
|
69
|
-
if not np.isclose(a1, a2, rtol=
|
70
|
-
logger.debug("alpha NOT close (%s/%s)", a1, a2)
|
87
|
+
if not np.isclose(a1, a2, rtol=1e-4, atol=1e-2):
|
88
|
+
logger.debug("equal_area: alpha NOT close (%s/%s)", a1, a2)
|
71
89
|
return False
|
90
|
+
else:
|
91
|
+
if a1 > a2:
|
92
|
+
f = a2 / a1
|
93
|
+
else:
|
94
|
+
f = a1 / a2
|
95
|
+
if f < 0.9:
|
96
|
+
return False
|
72
97
|
return True
|
73
98
|
|
74
99
|
def calc_mid_angle(self, a):
|
@@ -82,6 +107,8 @@ class Symmetry(object):
|
|
82
107
|
logger.debug("end of find_symmetry: no areas")
|
83
108
|
return 0
|
84
109
|
|
110
|
+
logger.debug("startangle=%s, endangle=%s", self.startangle, self.endangle)
|
111
|
+
|
85
112
|
areas = []
|
86
113
|
for a in arealist:
|
87
114
|
areas.append((round(a.get_alpha(self.geom.center), 3),
|
@@ -97,32 +124,42 @@ class Symmetry(object):
|
|
97
124
|
for a1_alpha, a1_min_dist, a1_height, a1_mid_angle, a1 in areas[1:]:
|
98
125
|
if self.equal_area(a0_min_dist, a0_height, a0_alpha,
|
99
126
|
a1_min_dist, a1_height, a1_alpha,
|
100
|
-
rtol=0.
|
127
|
+
rtol=0.001, atol=0.05):
|
101
128
|
a0_min_dist = (a0_min_dist + a1_min_dist) / 2
|
102
129
|
a0_height = (a0_height + a1_height) / 2
|
103
130
|
a0_alpha = (a0_alpha + a1_alpha) / 2
|
104
131
|
equal_areas.append((a1_mid_angle, a1))
|
105
132
|
else:
|
106
|
-
|
107
|
-
|
108
|
-
|
133
|
+
rslt = self.check_delta(equal_areas)
|
134
|
+
areasize = a0.area_size()
|
135
|
+
rslt['area'] = a0
|
136
|
+
rslt['areasize'] = areasize
|
137
|
+
check_rslt.append((areasize, rslt))
|
109
138
|
equal_areas = [(a1_mid_angle, a1)]
|
110
139
|
a0_min_dist = a1_min_dist
|
111
140
|
a0_height = a1_height
|
112
141
|
a0_alpha = a1_alpha
|
113
142
|
a0 = a1
|
114
143
|
|
115
|
-
|
116
|
-
|
144
|
+
rslt = self.check_delta(equal_areas)
|
145
|
+
areasize = a0.area_size()
|
146
|
+
rslt['area'] = a0
|
147
|
+
rslt['areasize'] = areasize
|
148
|
+
check_rslt.append((areasize, rslt))
|
117
149
|
|
118
|
-
parts = self.get_symmetry_parts(check_rslt)
|
150
|
+
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
119
151
|
if parts < 2:
|
120
152
|
logger.debug("end of Symmetry::find_symmetry: no symmetry")
|
121
153
|
return parts
|
122
154
|
|
155
|
+
if self.delta_angle_corr is not None and self.delta_angle_corr != 0.0:
|
156
|
+
self.startangle = self.startangle - self.delta_angle_corr
|
157
|
+
self.endangle = self.endangle - self.delta_angle_corr
|
158
|
+
|
123
159
|
self.geom.clear_cut_lines()
|
124
160
|
for alpha in self.symmetry_lines(parts,
|
125
161
|
self.startangle,
|
162
|
+
start_delta,
|
126
163
|
self.endangle):
|
127
164
|
plus = self.geom.max_radius / 10
|
128
165
|
min_radius = max(10, self.geom.min_radius - plus)
|
@@ -134,19 +171,29 @@ class Symmetry(object):
|
|
134
171
|
|
135
172
|
logger.debug("end of Symmetry::find_symmetry: -> %s", parts)
|
136
173
|
return parts
|
137
|
-
|
174
|
+
|
138
175
|
def check_delta(self, area_list):
|
139
176
|
logger.debug("begin of check_delta: %s equal areas", len(area_list))
|
177
|
+
result = {'areas': len(area_list),
|
178
|
+
'startdelta': 0.0,
|
179
|
+
'slices': None}
|
140
180
|
if not area_list:
|
141
181
|
logger.debug("end of check_delta: no areas")
|
142
|
-
return
|
182
|
+
return result
|
143
183
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
184
|
+
rtol = 1e-3
|
185
|
+
atol = 1e-2
|
186
|
+
|
187
|
+
logger.debug("Geometry: Alpha=%s, Center=%s", self.alpha, self.geom.center)
|
188
|
+
mid_angle, a = area_list[0]
|
189
|
+
result['height'] = a.height
|
190
|
+
result['alpha'] = a.get_alpha(self.geom.center)
|
191
|
+
if self.geom.is_inner:
|
192
|
+
result['airgap'] = np.isclose(a.max_dist, self.ag_radius)
|
193
|
+
else:
|
194
|
+
result['airgap'] = np.isclose(a.min_dist, self.ag_radius)
|
195
|
+
if len(area_list) == 1: # one area
|
196
|
+
return self.check_one_area(mid_angle, a, result, rtol=rtol, atol=atol)
|
150
197
|
|
151
198
|
self.delta_check_count += 1
|
152
199
|
area_list.sort()
|
@@ -154,8 +201,9 @@ class Symmetry(object):
|
|
154
201
|
mid_angle, a = area_list[0]
|
155
202
|
delta = positive_angle(mid_angle * 2)
|
156
203
|
delta_total = mid_angle
|
204
|
+
logger.debug("first delta=%s, total=%s", delta, delta_total)
|
157
205
|
delta_list = [delta]
|
158
|
-
|
206
|
+
mid_delta_list = [(mid_angle, delta)]
|
159
207
|
logger.debug("First mid = %s, delta = %s", mid_angle, delta)
|
160
208
|
logger.debug("%s: d=%s, h=%s, a=%s, mid=%s, delta=%s",
|
161
209
|
a.identifier(),
|
@@ -173,7 +221,10 @@ class Symmetry(object):
|
|
173
221
|
delta_angle = alpha_angle(start_angle, mid_angle)
|
174
222
|
delta = positive_angle(delta_angle)
|
175
223
|
delta_total += delta_angle
|
224
|
+
logger.debug("next delta=%s, total=%s", delta, delta_total)
|
225
|
+
|
176
226
|
delta_list.append(delta)
|
227
|
+
mid_delta_list.append((mid_angle, delta))
|
177
228
|
|
178
229
|
logger.debug("%s: d=%s, h=%s, a=%s, mid=%s, delta=%s",
|
179
230
|
a.identifier(),
|
@@ -185,103 +236,587 @@ class Symmetry(object):
|
|
185
236
|
start_angle = mid_angle
|
186
237
|
|
187
238
|
delta_angle = alpha_angle(start_angle, geom_alpha)
|
239
|
+
if np.isclose(delta_angle, np.pi*2, rtol=1e-4, atol=1e-4):
|
240
|
+
logger.debug("Last Area is in the middle of endangle")
|
241
|
+
delta_angle = 0.0
|
188
242
|
delta = positive_angle(delta_angle * 2)
|
189
243
|
delta_total += delta_angle
|
190
244
|
delta_list.append(delta)
|
191
|
-
|
245
|
+
mid_delta_list.append((0.0, delta))
|
246
|
+
|
247
|
+
logger.debug("final delta=%s, total=%s", delta, delta_total)
|
248
|
+
logger.debug("Delta List: %s", delta_list)
|
249
|
+
logger.debug("Mid Delta List")
|
250
|
+
[logger.debug("-- Mid angle: %s, Delta: %s", a, d) for a, d in mid_delta_list]
|
192
251
|
|
193
|
-
if not np.isclose(geom_alpha, delta_total):
|
252
|
+
if not np.isclose(geom_alpha, delta_total, rtol=rtol, atol=atol):
|
194
253
|
logger.debug("-- deltas: %s", delta_list)
|
195
254
|
logger.debug("end of check_delta: BAD DELTA %s, (expected %s)",
|
196
255
|
delta_angle, geom_alpha)
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
256
|
+
result['slices'] = 0
|
257
|
+
return result # very bad
|
258
|
+
|
259
|
+
deltas = self.create_deltas(delta_list, rtol=rtol, atol=atol)
|
260
|
+
|
261
|
+
logger.debug("Start with looking for symmetry")
|
262
|
+
|
263
|
+
logger.debug(">> %s Deltas <<", len(deltas))
|
264
|
+
[logger.debug(" -- n=%s, delta=%s", n, d) for n, d in deltas]
|
265
|
+
|
266
|
+
if len(deltas) == 2:
|
267
|
+
n1, d1 = deltas[0]
|
268
|
+
n2, d2 = deltas[1]
|
269
|
+
logger.debug("delta 1: n=%s, delta=%s", n1, d1)
|
270
|
+
logger.debug("delta 2: n=%s, delta=%s", n2, d2)
|
271
|
+
|
272
|
+
if n2 == 2 and n1 > 2 and \
|
273
|
+
np.isclose(d1, d2 / 2.0, rtol=rtol, atol=atol):
|
274
|
+
if np.isclose(d2, delta_list[0], rtol=rtol, atol=atol) and \
|
275
|
+
np.isclose(d2, delta_list[-1], rtol=rtol, atol=atol):
|
276
|
+
slices = n1 + n2
|
277
|
+
if slices > 4:
|
278
|
+
result['slices'] = slices
|
279
|
+
else:
|
280
|
+
result['slices'] = 1
|
281
|
+
result['slices_half'] = slices
|
282
|
+
result['halfslice'] = 1
|
283
|
+
result['startdelta'] = d1 / 2
|
284
|
+
logger.debug("#3: end of check_delta: SYMMETRY FOUND [%s] halfslice",
|
285
|
+
result['slices'])
|
286
|
+
return result
|
287
|
+
|
288
|
+
elif n1 == 2 and n2 == 1:
|
289
|
+
assert(len(area_list) == 2)
|
290
|
+
semi_alpha = result['alpha'] / 2
|
291
|
+
a0_mid_angle, a0 = area_list[0]
|
292
|
+
a1_mid_angle, a1 = area_list[1]
|
293
|
+
a0_start = np.isclose(a0_mid_angle - semi_alpha,
|
294
|
+
0.0,
|
295
|
+
rtol=rtol, atol=atol)
|
296
|
+
a1_end = np.isclose(a1_mid_angle + semi_alpha,
|
297
|
+
self.alpha,
|
298
|
+
rtol=rtol, atol=atol)
|
299
|
+
if a0_start and a1_end and d1 < d2:
|
300
|
+
result['slices'] = 0
|
301
|
+
result['halfslice'] = 2
|
302
|
+
logger.debug("#4: end of check_delta: half slices")
|
303
|
+
return result
|
304
|
+
|
305
|
+
if not a0_start and not a1_end and d1 > d2:
|
306
|
+
parts_in_circ = part_of_circle(0.0, d2, 1)
|
307
|
+
parts_in_geom = float(round(parts_in_circ / self.geom_part, 2))
|
308
|
+
if parts_in_geom.is_integer():
|
309
|
+
parts_in_geom = int(parts_in_geom)
|
310
|
+
else:
|
311
|
+
parts_in_geom = 0
|
312
|
+
result['slices'] = parts_in_geom
|
313
|
+
result['slices_half'] = parts_in_geom
|
314
|
+
result['halfslice'] = 1
|
315
|
+
logger.debug("#5: end of check_delta: SYMMETRY FOUND [%s] halfslice",
|
316
|
+
result['slices'])
|
317
|
+
return result
|
318
|
+
|
319
|
+
elif abs(n1 - n2) == 1:
|
320
|
+
if d1 < d2:
|
321
|
+
if self.check_pairs_in_delta_list(delta_list,
|
322
|
+
deltas,
|
323
|
+
rtol=rtol, atol=atol):
|
324
|
+
result['slices'] = int(len(area_list) / 2)
|
325
|
+
delta_angle_corr = (d1 + d2) / 2
|
326
|
+
result['delta_corr'] = delta_angle_corr
|
327
|
+
logger.debug("Startangle correction by %s", delta_angle_corr)
|
328
|
+
logger.debug("#6: end of check_delta: SYMMETRY FOUND [%s]",
|
329
|
+
result['slices'])
|
330
|
+
return result
|
331
|
+
|
332
|
+
if len(deltas) > 1:
|
333
|
+
n1, d1 = deltas[0]
|
334
|
+
n2, d2 = deltas[1]
|
335
|
+
if n1 + n2 + 1 == len(area_list) and abs(n1 - n2) == 1:
|
336
|
+
dlist = self.check_pairs_of_areas(mid_delta_list,
|
337
|
+
min(d1, d2),
|
338
|
+
geom_alpha,
|
339
|
+
rtol=rtol, atol=atol)
|
340
|
+
if dlist:
|
341
|
+
delta_list = dlist
|
342
|
+
deltas = self.create_deltas(delta_list, rtol=rtol, atol=atol)
|
343
|
+
|
344
|
+
if False:
|
345
|
+
parts_in_circ = part_of_circle(0.0, d1, 1)
|
346
|
+
parts_in_geom = float(round(parts_in_circ / self.geom_part, 2))
|
347
|
+
if parts_in_geom.is_integer():
|
348
|
+
parts_in_geom = int(parts_in_geom)
|
349
|
+
else:
|
350
|
+
parts_in_geom = 0
|
351
|
+
|
352
|
+
if parts_in_geom / n1 > 0.75 and parts_in_circ > 15:
|
353
|
+
result['slices'] = parts_in_geom
|
354
|
+
logger.debug("#7: end of check_delta: SYMMETRY FOUND [%s]",
|
355
|
+
result['slices'])
|
356
|
+
return result
|
357
|
+
|
358
|
+
missing_middle = []
|
359
|
+
if len(deltas) == 2:
|
360
|
+
logger.debug("looking for holes in delta list")
|
361
|
+
|
362
|
+
delta_n, delta_value = deltas[0]
|
363
|
+
logger.debug("First n,v == (%s, %s)", delta_n, delta_value)
|
364
|
+
for n, v in deltas[1:]:
|
365
|
+
logger.debug("Next n,v == (%s, %s)", n, v)
|
366
|
+
if n < delta_n / 4 and \
|
367
|
+
np.isclose(delta_value, v / 2.0, rtol=1e-04, atol=1e-03):
|
368
|
+
logger.debug("Hole found")
|
369
|
+
inx = [i for i, x in enumerate(delta_list)
|
370
|
+
if np.isclose(x, v, rtol=rtol, atol=atol)]
|
371
|
+
if len(inx) != n:
|
372
|
+
logger.debug("Hole missmatch: %s <> %s", len(inx), n)
|
373
|
+
result['slices'] = 0
|
374
|
+
return result
|
375
|
+
|
376
|
+
dlist = []
|
377
|
+
x = 0
|
378
|
+
# logger.info("inx: %s", inx)
|
379
|
+
# [logger.info("%s deltas: %s", n, d) for n, d in deltas]
|
380
|
+
# [logger.info("area: %s", m) for m, a in area_list]
|
381
|
+
|
382
|
+
for i in inx:
|
383
|
+
for n in range(x, i):
|
384
|
+
logger.debug("set value of index %s", n)
|
385
|
+
dlist.append(delta_list[n])
|
386
|
+
m1, a = area_list[i-1]
|
387
|
+
if i < len(area_list):
|
388
|
+
m2, a = area_list[i]
|
389
|
+
else:
|
390
|
+
m2, a = area_list[0]
|
391
|
+
mid = (m1 + m2) / 2
|
392
|
+
logger.debug("Missing mid is %s", mid)
|
393
|
+
missing_middle.append((mid, i))
|
394
|
+
x = i+1
|
395
|
+
logger.debug("set value in hole")
|
396
|
+
dlist.append(delta_value)
|
397
|
+
dlist.append(delta_value)
|
398
|
+
for n in range(x, len(delta_list)):
|
399
|
+
logger.debug("set value of index %s", n)
|
400
|
+
dlist.append(delta_list[n])
|
401
|
+
logger.debug("New List: %s", dlist)
|
402
|
+
delta_list = dlist
|
403
|
+
|
404
|
+
result['middlelist'] = [m for m, a in area_list]
|
405
|
+
result['missing_middles'] = missing_middle
|
406
|
+
|
407
|
+
if not np.isclose(delta_list[0], delta_list[-1], rtol=rtol, atol=atol):
|
408
|
+
logger.debug("First and Last delta not equal")
|
409
|
+
if self.full:
|
410
|
+
d0 = (delta_list[0] + delta_list[-1]) / 2
|
411
|
+
n1, d1 = deltas[0]
|
412
|
+
if np.isclose(d0, d1, rtol=rtol, atol=atol):
|
413
|
+
delta_angle_corr = (d0 - delta_list[0]) / 2
|
414
|
+
result['delta_corr'] = delta_angle_corr
|
415
|
+
logger.debug("Startangle correction by %s", delta_angle_corr)
|
416
|
+
delta_list[0] = d0
|
417
|
+
delta_list[-1] = d0
|
418
|
+
else:
|
419
|
+
parts = self.check_first_last_difference(delta_list, deltas)
|
420
|
+
if parts > 0:
|
421
|
+
result['slices'] = parts
|
422
|
+
logger.debug("#8: end of check_delta: SYMMETRY FOUND [%s]",
|
423
|
+
result['slices'])
|
424
|
+
return result
|
425
|
+
|
426
|
+
logger.debug("Final Delta List: %s", delta_list)
|
230
427
|
d1 = delta_list[0]
|
231
428
|
d1_count = 1
|
232
429
|
inx_list = [0]
|
233
430
|
for x in range(1, len(delta_list)):
|
234
|
-
if np.isclose(d1, delta_list[x], rtol=
|
431
|
+
if np.isclose(d1, delta_list[x], rtol=rtol, atol=atol):
|
235
432
|
inx_list.append(x)
|
236
433
|
d1_count += 1
|
237
434
|
|
238
435
|
if d1_count == len(delta_list):
|
239
|
-
|
240
|
-
|
241
|
-
|
436
|
+
result['slices'] = d1_count -1
|
437
|
+
logger.debug("#9: end of check_delta: SYMMETRY FOUND [%s]",
|
438
|
+
result['slices'])
|
439
|
+
return result # very simple
|
440
|
+
if len(delta_list) < 3:
|
242
441
|
logger.debug("end of check_delta: One delta only ?!")
|
243
|
-
|
442
|
+
result['slices'] = 0
|
443
|
+
return result
|
444
|
+
|
445
|
+
logger.debug("index of delta %s: %s", d1, inx_list)
|
446
|
+
if len(inx_list) < 2:
|
447
|
+
logger.debug("end of check_delta: NO SYMMETRY")
|
448
|
+
result['slices'] = 0
|
449
|
+
return result
|
244
450
|
|
245
|
-
logger.debug("index of delta %s = %s", d1, inx_list)
|
246
451
|
x1 = inx_list[0]
|
247
452
|
x2 = inx_list[1]
|
248
453
|
step = x2 - x1
|
249
454
|
x1 = x2
|
250
455
|
for x2 in inx_list[2:]:
|
251
456
|
if not (x2 - x1 == step):
|
252
|
-
|
457
|
+
logger.debug("end of check_delta: NO SYMMETRY")
|
458
|
+
result['slices'] = 0
|
459
|
+
return result
|
253
460
|
x1 = x2
|
254
|
-
|
255
|
-
logger.debug("
|
256
|
-
|
461
|
+
|
462
|
+
logger.debug("length of delta %s: %s",
|
463
|
+
len(inx_list),
|
464
|
+
inx_list)
|
465
|
+
result['slices'] = len(inx_list) -1
|
466
|
+
logger.debug("#10: end of check_delta: SYMMETRY FOUND [%s]", result['slices'])
|
467
|
+
return result
|
468
|
+
|
469
|
+
def create_deltas(self, delta_list, rtol=1e-3, atol=1e-2):
|
470
|
+
delta_list_sorted = [d for d in delta_list]
|
471
|
+
delta_list_sorted.sort()
|
472
|
+
delta = delta_list_sorted[0]
|
473
|
+
delta_n = 1
|
474
|
+
deltas = []
|
475
|
+
for i in range(1,len(delta_list_sorted)):
|
476
|
+
if np.isclose(delta_list_sorted[i], delta, rtol=rtol, atol=atol):
|
477
|
+
delta = (delta + delta_list_sorted[i]) / 2
|
478
|
+
delta_n += 1
|
479
|
+
else:
|
480
|
+
deltas.append((delta_n, delta))
|
481
|
+
delta = delta_list_sorted[i]
|
482
|
+
delta_n = 1
|
483
|
+
deltas.append((delta_n, delta))
|
484
|
+
deltas.sort(reverse=True)
|
485
|
+
return deltas
|
486
|
+
|
487
|
+
def check_one_area(self, mid_angle, a, result, rtol=1e-3, atol=1e-2):
|
488
|
+
logger.debug("begin of check_one_area")
|
489
|
+
|
490
|
+
alpha = a.get_alpha(self.geom.center)
|
491
|
+
logger.debug("Single %s: d=%s, h=%s, a=%s, mid=%s",
|
492
|
+
a.identifier(),
|
493
|
+
a.min_dist,
|
494
|
+
a.height,
|
495
|
+
a.get_alpha(self.geom.center),
|
496
|
+
mid_angle)
|
497
|
+
if np.isclose(alpha, self.alpha, rtol=rtol, atol=atol):
|
498
|
+
logger.debug("end of check_one_area: area %s from start to end",
|
499
|
+
a.identifier())
|
500
|
+
result['slices'] = None
|
501
|
+
return result # ok
|
502
|
+
|
503
|
+
if self.full:
|
504
|
+
result['slices'] = 1
|
505
|
+
logger.debug("end of check_one_area: full with 1 slice")
|
506
|
+
return result
|
507
|
+
|
508
|
+
delta_angle = alpha_angle(self.startangle, mid_angle)
|
509
|
+
delta1 = positive_angle(delta_angle)
|
510
|
+
delta_angle = alpha_angle(mid_angle, self.endangle)
|
511
|
+
delta2 = positive_angle(delta_angle)
|
512
|
+
if np.isclose(delta1, delta2, rtol=rtol, atol=atol):
|
513
|
+
result['slices'] = 1
|
514
|
+
result['slices_half'] = 2
|
515
|
+
result['halfslice'] = 1
|
516
|
+
logger.debug("end of check_delta: One Area in the middle")
|
517
|
+
else:
|
518
|
+
result['middlelist'] = [mid_angle]
|
519
|
+
result['slices'] = 0
|
520
|
+
logger.debug("end of check_one_area: Area somewhere")
|
521
|
+
return result
|
522
|
+
|
523
|
+
def check_pairs_in_delta_list(self,
|
524
|
+
delta_list,
|
525
|
+
deltas,
|
526
|
+
rtol=1e-3, atol=1e-2):
|
527
|
+
if len(deltas) < 2:
|
528
|
+
return False
|
529
|
+
if len(delta_list) < 5:
|
530
|
+
return False
|
531
|
+
n1, d1 = deltas[0]
|
532
|
+
n2, d2 = deltas[1]
|
533
|
+
if not abs(n1 - n2) == 1:
|
534
|
+
return False
|
535
|
+
# check without first/last
|
536
|
+
delta0 = delta_list[1]
|
537
|
+
delta1 = delta_list[2]
|
538
|
+
for delta2 in delta_list[3:-1]:
|
539
|
+
if not np.isclose(delta0, delta2, rtol=rtol, atol=atol):
|
540
|
+
return False
|
541
|
+
delta0 = delta1
|
542
|
+
delta1 = delta2
|
543
|
+
logger.debug("** Pairs available **")
|
544
|
+
return True
|
545
|
+
|
546
|
+
def check_pairs_of_areas(self,
|
547
|
+
mid_delta_list,
|
548
|
+
delta,
|
549
|
+
geom_alpha,
|
550
|
+
rtol=1e-3, atol=1e-2):
|
551
|
+
logger.debug("begin of check_pairs_of_areas")
|
552
|
+
if len(mid_delta_list) < 2:
|
553
|
+
return None
|
554
|
+
|
555
|
+
logger.debug("Mid-Delta-List")
|
556
|
+
[logger.debug(" -- mid=%s, delta=%s",m, d) for m, d in mid_delta_list]
|
557
|
+
|
558
|
+
# check
|
559
|
+
mid_list = []
|
560
|
+
m0, d0 = mid_delta_list[0]
|
561
|
+
m1, d1 = mid_delta_list[1]
|
562
|
+
if np.isclose(delta, d1, rtol=rtol, atol=atol):
|
563
|
+
mx = (m0 + m1) / 2
|
564
|
+
mid_list.append(mx)
|
565
|
+
|
566
|
+
m0, d0 = mid_delta_list[2]
|
567
|
+
dx = d1
|
568
|
+
for m2, d2 in mid_delta_list[2:-1]:
|
569
|
+
#logger.debug("compare %s and %s", d0, d2)
|
570
|
+
if not np.isclose(d0, d2, rtol=rtol, atol=atol):
|
571
|
+
logger.debug("end of check_pairs_of_areas: bad pairs")
|
572
|
+
return None
|
573
|
+
if np.isclose(delta, d2, rtol=rtol, atol=atol):
|
574
|
+
mx = (m1 + m2) / 2
|
575
|
+
mid_list.append(mx)
|
576
|
+
d0 = d1
|
577
|
+
m1 = m2
|
578
|
+
d1 = d2
|
579
|
+
|
580
|
+
logger.debug("New Mids: %s", mid_list)
|
581
|
+
delta = positive_angle(mid_list[0] * 2)
|
582
|
+
delta_list = [delta]
|
583
|
+
m0 = mid_list[0]
|
584
|
+
for m1 in mid_list[1:]:
|
585
|
+
delta = positive_angle(alpha_angle(m0, m1))
|
586
|
+
delta_list.append(delta)
|
587
|
+
m0 = m1
|
588
|
+
|
589
|
+
delta_angle = alpha_angle(m1, geom_alpha)
|
590
|
+
if np.isclose(delta_angle, np.pi*2, rtol=1e-4, atol=1e-4):
|
591
|
+
logger.debug("Last Area is in the middle of endangle")
|
592
|
+
delta_angle = 0.0
|
593
|
+
delta = positive_angle(delta_angle * 2)
|
594
|
+
delta_list.append(delta)
|
595
|
+
logger.debug("New delta-list: %s", delta_list)
|
596
|
+
logger.debug("end of check_pairs_of_areas")
|
597
|
+
return delta_list
|
598
|
+
|
599
|
+
def check_first_last_difference(self, delta_list, deltas):
|
600
|
+
logger.debug("begin check_first_last_difference")
|
601
|
+
if np.isclose(delta_list[0], delta_list[-1],
|
602
|
+
rtol=self.rtol, atol=self.atol):
|
603
|
+
logger.debug("end check_first_last_difference: first/last equal")
|
604
|
+
return 0
|
605
|
+
if len(deltas) != 3:
|
606
|
+
logger.debug("end check_first_last_difference: not 3 deltas")
|
607
|
+
return 0
|
608
|
+
logger.debug(">> 3 Deltas <<")
|
609
|
+
n1, d1 = deltas[0]
|
610
|
+
n2, d2 = deltas[1]
|
611
|
+
n3, d3 = deltas[2]
|
612
|
+
if not (n2 == 1 and n3 == 1):
|
613
|
+
logger.debug("end check_first_last_difference: first/last diff")
|
614
|
+
return 0
|
615
|
+
dx = (d2 + d3) / 2
|
616
|
+
if not np.isclose(dx, d1, rtol=self.rtol, atol=self.atol):
|
617
|
+
logger.debug("end check_first_last_difference: bad deltas")
|
618
|
+
return 0
|
619
|
+
dx = (delta_list[0] + delta_list[-1]) / 2
|
620
|
+
if not np.isclose(dx, d1, rtol=self.rtol, atol=self.atol):
|
621
|
+
logger.debug("end check_first_last_difference: bad deltas")
|
622
|
+
return 0
|
623
|
+
|
624
|
+
logger.debug("end check_first_last_difference => %s", n1 + 1)
|
625
|
+
return n1 + 1
|
257
626
|
|
258
627
|
def get_symmetry_parts(self, check_rslt):
|
259
628
|
max_size = 0
|
260
629
|
max_areas = 0
|
630
|
+
max_slices = 0
|
261
631
|
parts_possible = None
|
632
|
+
self.delta_angle_corr = None
|
633
|
+
unsure_sym = False
|
262
634
|
|
635
|
+
check_rslt = [(size, n, rslt) for n, (size, rslt) in enumerate(check_rslt)]
|
263
636
|
check_rslt.sort(reverse=True)
|
264
|
-
for size,
|
265
|
-
logger.debug("Result: %s, %s
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
637
|
+
for size, n, rslt in check_rslt:
|
638
|
+
logger.debug("Result: %s, %s", size, rslt)
|
639
|
+
|
640
|
+
rtol = 1e-3
|
641
|
+
atol = 1e-2
|
642
|
+
|
643
|
+
missing_middles = []
|
644
|
+
halfslice = []
|
645
|
+
start_delta = None
|
646
|
+
start_delta_corr = 0.0
|
647
|
+
|
648
|
+
with_angle_corr = 0
|
649
|
+
without_angle_corr = 0
|
650
|
+
maybe_angle_korr = 0
|
651
|
+
|
652
|
+
for size, n, rslt in check_rslt:
|
653
|
+
areas = rslt['areas']
|
654
|
+
slices = rslt['slices']
|
655
|
+
size = rslt['areasize']
|
656
|
+
angle_corr = rslt.get('delta_corr', 0.0)
|
657
|
+
|
658
|
+
if rslt.get('halfslice', 0) == 1:
|
659
|
+
halfslice.append(rslt)
|
660
|
+
|
661
|
+
if slices is not None:
|
662
|
+
if slices > 0:
|
663
|
+
max_size = max(max_size, size)
|
664
|
+
max_areas = max(max_areas, areas)
|
665
|
+
max_slices = max(max_slices, slices)
|
666
|
+
missing_middles += rslt.get('missing_middles', [])
|
667
|
+
area = rslt['area']
|
668
|
+
if not (np.isclose(area.min_dist,
|
669
|
+
self.geom.min_radius,
|
670
|
+
rtol=1e-4, atol=1e-3) and \
|
671
|
+
np.isclose(area.max_dist,
|
672
|
+
self.geom.max_radius,
|
673
|
+
rtol=1e-4, atol=1e-3)):
|
674
|
+
if rslt.get('delta_corr', 0.0) == 0.0:
|
675
|
+
without_angle_corr += areas * size
|
676
|
+
else:
|
677
|
+
with_angle_corr += areas * size
|
678
|
+
else:
|
679
|
+
maybe_angle_korr += areas * size
|
272
680
|
logger.debug("max size: %s, max areas: %s", max_size, max_areas)
|
273
681
|
|
274
|
-
|
275
|
-
|
276
|
-
|
682
|
+
logger.debug("Angle-Corrections: %s Yes, %s No",
|
683
|
+
with_angle_corr, without_angle_corr)
|
684
|
+
if np.isclose(with_angle_corr, without_angle_corr):
|
685
|
+
with_angle_corr = (maybe_angle_korr > 0)
|
686
|
+
else:
|
687
|
+
with_angle_corr = (with_angle_corr > without_angle_corr)
|
688
|
+
|
689
|
+
def get_halfslice_counterpart(rslt):
|
690
|
+
if rslt.get('halfslice', 0) != 2:
|
691
|
+
return None
|
692
|
+
for half in halfslice:
|
693
|
+
alpha1 = half['alpha']
|
694
|
+
height1 = half['height']
|
695
|
+
alpha2 = rslt['alpha'] * 2.0
|
696
|
+
height2 = rslt['height']
|
697
|
+
logger.debug("-- height: %s / %s", height1, height2)
|
698
|
+
logger.debug("-- alpha: %s / %s", alpha1, alpha2)
|
699
|
+
if np.isclose(height1, height2, rtol=rtol, atol=atol) and \
|
700
|
+
np.isclose(alpha1, alpha2, rtol=rtol, atol=atol):
|
701
|
+
return half
|
702
|
+
return None
|
703
|
+
|
704
|
+
if halfslice:
|
705
|
+
logger.debug("%s halfslice [1] found", len(halfslice))
|
706
|
+
|
707
|
+
for size, n, rslt in check_rslt:
|
708
|
+
half = get_halfslice_counterpart(rslt)
|
709
|
+
if half:
|
710
|
+
logger.debug("Halfslice counterpart found")
|
711
|
+
alpha1 = half['alpha']
|
712
|
+
height1 = half['height']
|
713
|
+
alpha2 = rslt['alpha'] * 2.0
|
714
|
+
height2 = rslt['height']
|
715
|
+
logger.debug("-- height: %s / %s", height1, height2)
|
716
|
+
logger.debug("-- alpha: %s / %s", alpha1, alpha2)
|
717
|
+
if np.isclose(height1, height2, rtol=rtol, atol=atol) and \
|
718
|
+
np.isclose(alpha1, alpha2, rtol=rtol, atol=atol):
|
719
|
+
logger.debug("halfslice result: %s", half)
|
720
|
+
slices = None
|
721
|
+
rslt['slices'] = slices
|
722
|
+
half['slices'] = half['slices_half']
|
723
|
+
|
724
|
+
angle_corr_slices = 0
|
725
|
+
angle_corr_size = 0
|
726
|
+
angle_corr_areas = 0
|
727
|
+
angle_corr_airgap = False
|
728
|
+
|
729
|
+
for size, n, rslt in check_rslt:
|
730
|
+
areas = rslt['areas']
|
731
|
+
slices = rslt['slices']
|
732
|
+
size = rslt['areasize']
|
733
|
+
|
734
|
+
if slices is None: # ignore it
|
735
|
+
continue
|
736
|
+
|
737
|
+
delta_angle_corr = rslt.get('delta_corr', 0.0)
|
738
|
+
# Angle Correction
|
739
|
+
if with_angle_corr and self.delta_angle_corr is None:
|
740
|
+
self.delta_angle_corr = delta_angle_corr
|
741
|
+
angle_corr_slices = slices
|
742
|
+
angle_corr_size = size
|
743
|
+
angle_corr_areas = areas
|
744
|
+
angle_corr_airgap = rslt.get('airgap', False)
|
745
|
+
else:
|
746
|
+
if with_angle_corr and self.delta_angle_corr != delta_angle_corr:
|
747
|
+
unsure_sym = True
|
748
|
+
if slices > angle_corr_slices and \
|
749
|
+
size > angle_corr_size * 0.5:
|
750
|
+
logger.debug("Angle Correction")
|
751
|
+
self.delta_angle_corr = delta_angle_corr
|
752
|
+
angle_corr_slices = slices
|
753
|
+
angle_corr_size = size
|
754
|
+
angle_corr_areas = areas
|
755
|
+
angle_corr_airgap = rslt.get('airgap', False)
|
756
|
+
elif angle_corr_airgap and \
|
757
|
+
slices >= angle_corr_slices and \
|
758
|
+
areas > angle_corr_areas and \
|
759
|
+
size > angle_corr_size * 0.2:
|
760
|
+
logger.debug("Angle Correction")
|
761
|
+
self.delta_angle_corr = delta_angle_corr
|
762
|
+
angle_corr_slices = slices
|
763
|
+
angle_corr_size = size
|
764
|
+
angle_corr_areas = areas
|
765
|
+
angle_corr_airgap = rslt.get('airgap', False)
|
766
|
+
if slices:
|
767
|
+
if start_delta is None:
|
768
|
+
start_delta = rslt['startdelta']
|
769
|
+
start_delta_corr = start_delta
|
770
|
+
elif not rslt['startdelta'] != 0.0:
|
771
|
+
if start_delta_corr == 0.0:
|
772
|
+
start_delta_corr = rslt['startdelta']
|
773
|
+
elif not np.isclose(rslt['startdelta'], start_delta_corr,
|
774
|
+
rtol=rtol, atol=atol):
|
775
|
+
slices = 0 # bad
|
776
|
+
rslt['slices'] = slices
|
777
|
+
|
778
|
+
if slices is not None and slices <= 1: # critical
|
779
|
+
if areas <= max(1, max_areas / 5):
|
277
780
|
if size < max_size / 25:
|
278
|
-
|
781
|
+
slices = None
|
782
|
+
if slices == 0:
|
783
|
+
middles = rslt.get("middlelist", [])
|
784
|
+
if self.check_missing_areas(middles,
|
785
|
+
missing_middles):
|
786
|
+
logger.debug("Symmetry-Destroyer destroyed")
|
787
|
+
slices = None
|
279
788
|
|
280
|
-
|
789
|
+
if slices == 1:
|
790
|
+
# symmetry killer
|
791
|
+
if areas < max(2, max_areas / 6):
|
792
|
+
if size < max_size * 0.05:
|
793
|
+
slices = None # ignore tiny areas
|
794
|
+
|
795
|
+
|
796
|
+
parts_possible = self.calc_parts(parts_possible, slices)
|
797
|
+
|
798
|
+
if unsure_sym:
|
799
|
+
logger.warning("Warning: unsure symmetry")
|
281
800
|
|
282
801
|
if parts_possible is None:
|
283
802
|
parts_possible = 0
|
284
|
-
return parts_possible
|
803
|
+
return parts_possible, start_delta
|
804
|
+
|
805
|
+
def check_missing_areas(self, middles, missing_middles):
|
806
|
+
logger.debug("check_missing_areas")
|
807
|
+
logger.debug(" -- mids = %s", middles)
|
808
|
+
logger.debug(" -- missing mids = %s", missing_middles)
|
809
|
+
if not missing_middles:
|
810
|
+
return False
|
811
|
+
if len(middles) == 0 or len(middles) > 2:
|
812
|
+
return False
|
813
|
+
|
814
|
+
for m in middles:
|
815
|
+
mlist = [mm for mm, i in missing_middles
|
816
|
+
if np.isclose(m, mm, rtol=1e-3, atol=1e-3)]
|
817
|
+
if not mlist:
|
818
|
+
return False
|
819
|
+
return True
|
285
820
|
|
286
821
|
def calc_parts(self, parts1, parts2):
|
287
822
|
logger.debug("Calc symmetry Parts (%s, %s)", parts1, parts2)
|
@@ -298,15 +833,23 @@ class Symmetry(object):
|
|
298
833
|
logger.debug("return %s parts", parts)
|
299
834
|
return parts
|
300
835
|
|
301
|
-
def symmetry_lines(self, parts, startangle, endangle):
|
302
|
-
logger.debug("begin symmetry_lines from %s to %s",
|
836
|
+
def symmetry_lines(self, parts, startangle, start_delta, endangle):
|
837
|
+
logger.debug("begin symmetry_lines from %s to %s with start %s",
|
303
838
|
startangle,
|
304
|
-
endangle
|
839
|
+
endangle,
|
840
|
+
start_delta)
|
841
|
+
|
305
842
|
if less_equal(endangle, startangle):
|
306
843
|
endangle += 2*np.pi
|
307
844
|
|
308
|
-
|
309
|
-
|
845
|
+
sym = self.geom_part * parts
|
846
|
+
delta = 2*np.pi/sym
|
847
|
+
if start_delta == 0.0:
|
848
|
+
if not is_same_angle(startangle, endangle):
|
849
|
+
start_delta = delta
|
850
|
+
|
851
|
+
sym_startangle = startangle + start_delta
|
852
|
+
start = startangle + start_delta
|
310
853
|
while less(start, endangle):
|
311
854
|
yield start
|
312
855
|
start += delta
|
@@ -315,8 +858,8 @@ class Symmetry(object):
|
|
315
858
|
yield start
|
316
859
|
|
317
860
|
# Damit man anschliessend ohne Umstände schneiden kann.
|
318
|
-
self.geom.sym_startangle =
|
319
|
-
self.geom.sym_endangle =
|
861
|
+
self.geom.sym_startangle = sym_startangle
|
862
|
+
self.geom.sym_endangle = sym_startangle + delta
|
320
863
|
self.geom.sym_slices = parts
|
321
864
|
self.geom.sym_slice_angle = delta
|
322
865
|
self.geom.sym_area = Area([], (0,0), 0.0)
|
@@ -332,39 +875,65 @@ class Symmetry(object):
|
|
332
875
|
axis_m = line_m(self.geom.center, axis_p)
|
333
876
|
axis_n = line_n(self.geom.center, axis_m)
|
334
877
|
|
335
|
-
def counterpart_found(node, nodes, rtol, atol):
|
336
|
-
|
878
|
+
def counterpart_found(node, mirror_node, nodes, rtol, atol):
|
879
|
+
hit_sloppy = 0
|
337
880
|
for n in nodes:
|
338
|
-
if points_are_close(
|
339
|
-
logger.debug(" ---- %s is %s", node,
|
340
|
-
return
|
341
|
-
|
881
|
+
if points_are_close(mirror_node, n, rtol, atol):
|
882
|
+
logger.debug(" ---- %s is %s", node, mirror_node)
|
883
|
+
return 1, 1
|
884
|
+
if points_are_close(round_point(mirror_node, 1),
|
885
|
+
round_point(n, 1),
|
886
|
+
rtol, atol):
|
887
|
+
logger.debug(" ++++ %s is %s", node, mirror_node)
|
888
|
+
hit_sloppy = 1
|
889
|
+
|
890
|
+
logger.debug(" >>>> %s is NOT %s (%s)",
|
891
|
+
node, mirror_node, hit_sloppy)
|
892
|
+
return 0, hit_sloppy
|
342
893
|
|
343
894
|
def check_differences(geom, mirror_geom):
|
344
895
|
geom_ag_nodes = []
|
345
896
|
geom_nodes = [n for n in geom.g.nodes() if not (n in geom_ag_nodes)]
|
346
897
|
|
347
|
-
|
898
|
+
hits = 0
|
899
|
+
hits_sloppy = 0
|
348
900
|
for n in geom_nodes:
|
349
901
|
mirror_n = mirror_point(n, geom.center, axis_m, axis_n)
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
902
|
+
hit, hit_sloppy = counterpart_found(n, mirror_n,
|
903
|
+
mirror_geom.g.nodes(),
|
904
|
+
# self.rtol,
|
905
|
+
1e-3,
|
906
|
+
# self.atol):
|
907
|
+
1e-2)
|
908
|
+
hits += hit
|
909
|
+
hits_sloppy += hit_sloppy
|
910
|
+
|
355
911
|
min_nodes = min(len(geom_nodes), int(len(geom_nodes) * 0.95) + 1)
|
356
|
-
logger.debug("Nodes=%s, Counterparts=%s
|
357
|
-
|
358
|
-
|
912
|
+
logger.debug("Nodes=%s, Counterparts=%s (sloppy=%s)",
|
913
|
+
len(geom_nodes), hits, hits_sloppy)
|
914
|
+
if hits < min_nodes:
|
915
|
+
f = hits / len(geom_nodes)
|
359
916
|
else:
|
360
|
-
|
917
|
+
f = 1.0
|
918
|
+
if hits_sloppy < min_nodes:
|
919
|
+
f_sloppy = hits_sloppy / len(geom_nodes)
|
920
|
+
else:
|
921
|
+
f_sloppy = 1.0
|
922
|
+
return f, f_sloppy
|
361
923
|
|
362
924
|
# ----------------
|
363
925
|
logger.debug("check geom - mirror")
|
364
|
-
f1 = check_differences(self.geom, mirror_geom)
|
926
|
+
f1, f1_sloppy = check_differences(self.geom, mirror_geom)
|
365
927
|
logger.debug("check mirror - geom")
|
366
|
-
f2 = check_differences(mirror_geom, self.geom)
|
928
|
+
f2, f2_sloppy = check_differences(mirror_geom, self.geom)
|
367
929
|
logger.debug("Factor 1: %s, 2: %s", f1, f2)
|
368
|
-
|
930
|
+
if f1 >= 0.99 or f2 >= 0.99:
|
931
|
+
ok = not (f1 < 0.9 or f2 < 0.9)
|
932
|
+
else:
|
933
|
+
ok = f1 > 0.97 and f2 > 0.97
|
934
|
+
if not ok:
|
935
|
+
if f1_sloppy > 0.97 and f2_sloppy > 0.97:
|
936
|
+
logger.debug(" (A sloppy mirror found, but ignored)")
|
937
|
+
ok = True
|
369
938
|
logger.debug("end of Symmetry::check_symmetry_of_mirror => %s", ok)
|
370
939
|
return ok
|