pyMOTO 1.5.0__py3-none-any.whl → 1.5.1__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.
- {pyMOTO-1.5.0.dist-info → pyMOTO-1.5.1.dist-info}/METADATA +2 -2
- pyMOTO-1.5.1.dist-info/RECORD +29 -0
- pymoto/__init__.py +1 -1
- pymoto/common/domain.py +1 -0
- pymoto/common/dyadcarrier.py +1 -1
- pymoto/common/mma.py +11 -3
- pymoto/core_objects.py +98 -50
- pymoto/modules/assembly.py +17 -13
- pymoto/modules/io.py +17 -5
- pymoto/modules/linalg.py +14 -14
- pymoto/routines.py +2 -2
- pymoto/solvers/iterative.py +20 -16
- pymoto/solvers/solvers.py +44 -13
- pymoto/solvers/sparse.py +10 -0
- pyMOTO-1.5.0.dist-info/RECORD +0 -29
- {pyMOTO-1.5.0.dist-info → pyMOTO-1.5.1.dist-info}/LICENSE +0 -0
- {pyMOTO-1.5.0.dist-info → pyMOTO-1.5.1.dist-info}/WHEEL +0 -0
- {pyMOTO-1.5.0.dist-info → pyMOTO-1.5.1.dist-info}/top_level.txt +0 -0
- {pyMOTO-1.5.0.dist-info → pyMOTO-1.5.1.dist-info}/zip-safe +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pyMOTO
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.1
|
4
4
|
Summary: A modular approach for topology optimization
|
5
5
|
Home-page: https://github.com/aatmdelissen/pyMOTO
|
6
6
|
Author: Arnoud Delissen
|
@@ -51,7 +51,7 @@ automatically calculated.
|
|
51
51
|
|
52
52
|
# Quick start installation
|
53
53
|
1. Make sure you have Python running in some kind of virtual environment (e.g.
|
54
|
-
[conda](https://docs.conda.io/projects/conda/en/stable/), [miniconda](https://docs.conda.io/en/latest/miniconda.html),
|
54
|
+
[uv](https://docs.astral.sh/uv/guides/install-python/), [conda](https://docs.conda.io/projects/conda/en/stable/), [miniconda](https://docs.conda.io/en/latest/miniconda.html),
|
55
55
|
[venv](https://realpython.com/python-virtual-environments-a-primer/))
|
56
56
|
2. Install the pymoto Python package (and its dependencies)
|
57
57
|
- Option A (conda): If you are working with Conda, install by `conda install -c aatmdelissen pymoto`
|
@@ -0,0 +1,29 @@
|
|
1
|
+
pymoto/__init__.py,sha256=i4B3bc954raAJs0lh0vycgWQ3n6FQCL5oKllmaHtt8M,2058
|
2
|
+
pymoto/core_objects.py,sha256=JDY5OBnzSnmXp35-gY_Gqawjh6C2x8dL1cEV8KAW944,27343
|
3
|
+
pymoto/routines.py,sha256=inz5GbSnvmbD3WKmaNKATTc_SthKsAMPuRc8Jaub4xs,15568
|
4
|
+
pymoto/utils.py,sha256=YJ-PNLJLc12Yx6TYCrEechS2aaBRx0o4mTM1soeeyz0,1122
|
5
|
+
pymoto/common/domain.py,sha256=1peaQJuePBZCWjW2oMhRxlhOl1FuhthEE1aWW9dMumk,18168
|
6
|
+
pymoto/common/dyadcarrier.py,sha256=Q0MCIP4b-W_RuYxynvY-voCHfeZ4oF12ykAuVUnmLq4,19433
|
7
|
+
pymoto/common/mma.py,sha256=SaFdZhpL5uoQRLWxQrElcjRMzGG4CL3BcPc77z3eMVE,24612
|
8
|
+
pymoto/modules/aggregation.py,sha256=Oi17hIJ6dic4lOPw16zmjbdC72MjB6XK34H80bnbWAI,7580
|
9
|
+
pymoto/modules/assembly.py,sha256=o_HZ4bcyK6cMNWVsrmxvv2z6oDgQcrBmB6dquQCWGC8,23216
|
10
|
+
pymoto/modules/autodiff.py,sha256=WAfoAOHBSozf7jbr9gQz9Vw4a_2G9wGJxLMMqUQP0Co,1684
|
11
|
+
pymoto/modules/complex.py,sha256=B_Obk-ABdV66lEudZ5s8o6qG9NsmYlBsX-PbWvbphhc,4429
|
12
|
+
pymoto/modules/filter.py,sha256=6X9FaQMWYZ_TpHVTFiEibzlmAwmSWbydYM93LFrJ0Wo,25490
|
13
|
+
pymoto/modules/generic.py,sha256=YzsGZ8J0oLCORt78Bf2p0v4GuqpWRI77NLoCk7gqidw,10666
|
14
|
+
pymoto/modules/io.py,sha256=BHJgS5IvFTiYYH4cXqRwSid1bfB58HOQs_jhFeLbb3A,13639
|
15
|
+
pymoto/modules/linalg.py,sha256=GIMqcIfVsMib5nIwrhx4sPT6-auLiHBJjbKCAdulLLE,22005
|
16
|
+
pymoto/modules/scaling.py,sha256=uq88HHW9rP16XLz7UGc3CNBBpY2Z1glo8yjYxZEnXUg,2327
|
17
|
+
pymoto/solvers/__init__.py,sha256=9JUeD2SgZbkYFullA7s7s6SuAVv0onqAqJ8hFvNOs2g,1033
|
18
|
+
pymoto/solvers/auto_determine.py,sha256=X8MEG7h6jLfAV1inpja45_-suG8qQFMfLMDfW2ryQqQ,5134
|
19
|
+
pymoto/solvers/dense.py,sha256=9fKPCwNxRKAEk5k1A7fdLrr9ngeVssGlw-sbjWCm4iU,11235
|
20
|
+
pymoto/solvers/iterative.py,sha256=hfMRw2LChupr4sQf8qUKG6OHjhpeVAp6C9N7M4-845M,13179
|
21
|
+
pymoto/solvers/matrix_checks.py,sha256=bbrfjpTSWWnuQW3xY0_CYE8yrh5gA9K5b1LzHEOFAxI,1663
|
22
|
+
pymoto/solvers/solvers.py,sha256=Srn44oRonZIjJq-XVpJY9KoTWV0R7zBWFaSmXKWsUCw,11870
|
23
|
+
pymoto/solvers/sparse.py,sha256=BPw-2Q4lgbmtjCl8eLEmDdWhjqD7RSLrVYy_kQN_LdU,17144
|
24
|
+
pyMOTO-1.5.1.dist-info/LICENSE,sha256=ZXMC2Txpzs-dBwz9Me4_1rQCSVl4P1B27MomNi43F30,1072
|
25
|
+
pyMOTO-1.5.1.dist-info/METADATA,sha256=_ZZ3mHjsLTWtdHuM2k8VcO2t3xF6gt67gFVFHibXMJ8,5062
|
26
|
+
pyMOTO-1.5.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
27
|
+
pyMOTO-1.5.1.dist-info/top_level.txt,sha256=EdvAUSmFMaiqhuEZW8jxANMiK-LdPtlmDWL6SfmCdUU,7
|
28
|
+
pyMOTO-1.5.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
29
|
+
pyMOTO-1.5.1.dist-info/RECORD,,
|
pymoto/__init__.py
CHANGED
pymoto/common/domain.py
CHANGED
@@ -91,6 +91,7 @@ class DomainDefinition:
|
|
91
91
|
if self.nelz is None:
|
92
92
|
self.nelz = 0
|
93
93
|
self.unitx, self.unity, self.unitz = unitx, unity, unitz
|
94
|
+
self.origin = np.array([0.0, 0.0, 0.0])
|
94
95
|
|
95
96
|
self.dim = 1 if (self.nelz == 0 and self.nely == 0) else (2 if self.nelz == 0 else 3)
|
96
97
|
|
pymoto/common/dyadcarrier.py
CHANGED
@@ -393,7 +393,7 @@ class DyadCarrier(object):
|
|
393
393
|
exprvars = (rowvar, colvar) if mat is None else (rowvar, matvar, colvar)
|
394
394
|
expr = ','.join(exprvars) + '->' + batchvar
|
395
395
|
|
396
|
-
val = 0.0 if batchsize is None else np.zeros(batchsize)
|
396
|
+
val = 0.0 if batchsize is None else np.zeros(batchsize, dtype=np.result_type(mat, self.dtype))
|
397
397
|
for ui, vi in zip(self.u, self.v):
|
398
398
|
uarg = ui if rows is None else ui[rows]
|
399
399
|
varg = vi if cols is None else vi[cols]
|
pymoto/common/mma.py
CHANGED
@@ -305,8 +305,12 @@ class MMA:
|
|
305
305
|
|
306
306
|
# Setting up for constriants
|
307
307
|
self.m = len(self.responses) - 1
|
308
|
-
self.a = np.zeros(self.m)
|
309
|
-
|
308
|
+
self.a = kwargs.get("a", np.zeros(self.m))
|
309
|
+
if len(self.a) != self.m:
|
310
|
+
raise RuntimeError(f"Length of the a vector ({len(self.a)}) should be equal to # constraints ({self.m}).")
|
311
|
+
self.c = kwargs.get("c", np.full(self.m, self.cCoef, dtype=float))
|
312
|
+
if len(self.c) != self.m:
|
313
|
+
raise RuntimeError(f"Length of the c vector ({len(self.c)}) should be equal to # constraints ({self.m}).")
|
310
314
|
self.d = np.ones(self.m)
|
311
315
|
self.gold1 = np.zeros(self.m + 1)
|
312
316
|
self.gold2 = self.gold1.copy()
|
@@ -371,11 +375,15 @@ class MMA:
|
|
371
375
|
# Calculate response
|
372
376
|
self.funbl.response()
|
373
377
|
|
378
|
+
xval, _ = _concatenate_to_array([s.state for s in self.variables])
|
379
|
+
|
374
380
|
# Save response
|
375
381
|
f = ()
|
376
382
|
for s in self.responses:
|
377
383
|
if np.size(s.state) != 1:
|
378
384
|
raise TypeError("State of responses must be scalar.")
|
385
|
+
if np.iscomplexobj(s.state):
|
386
|
+
raise TypeError("Responses must be real-valued.")
|
379
387
|
f += (s.state, )
|
380
388
|
|
381
389
|
# Check function change convergence criterion
|
@@ -564,4 +572,4 @@ class MMA:
|
|
564
572
|
print(f" | Changes: {', '.join(change_msgs)}")
|
565
573
|
|
566
574
|
return xmma, change
|
567
|
-
|
575
|
+
|
pymoto/core_objects.py
CHANGED
@@ -186,14 +186,14 @@ class SignalSlice(Signal):
|
|
186
186
|
The sliced values are referenced to their original source Signal, such that they can be used and updated in modules.
|
187
187
|
This means that updating the values in this SignalSlice changes the data in its source Signal.
|
188
188
|
"""
|
189
|
-
def __init__(self,
|
190
|
-
self.
|
189
|
+
def __init__(self, base, sl, tag=None):
|
190
|
+
self.base = base
|
191
191
|
self.slice = sl
|
192
192
|
self.keep_alloc = False # Allocation must be False because sensitivity cannot be assigned with [] operator
|
193
193
|
|
194
194
|
# for s in slice:
|
195
195
|
if tag is None:
|
196
|
-
self.tag = f"{self.
|
196
|
+
self.tag = f"{self.base.tag}[{fmt_slice(self.slice)}]"
|
197
197
|
else:
|
198
198
|
self.tag = tag
|
199
199
|
|
@@ -203,7 +203,7 @@ class SignalSlice(Signal):
|
|
203
203
|
@property
|
204
204
|
def state(self):
|
205
205
|
try:
|
206
|
-
return None if self.
|
206
|
+
return None if self.base.state is None else self.base.state[self.slice]
|
207
207
|
except Exception as e:
|
208
208
|
# Possibilities: Unslicable object (TypeError) or Wrong dimensions or out of range (IndexError)
|
209
209
|
raise type(e)(str(e) + "\n\t| Above error was raised in SignalSlice.state (getter). Signal details:" +
|
@@ -212,7 +212,7 @@ class SignalSlice(Signal):
|
|
212
212
|
@state.setter
|
213
213
|
def state(self, new_state):
|
214
214
|
try:
|
215
|
-
self.
|
215
|
+
self.base.state[self.slice] = new_state
|
216
216
|
except Exception as e:
|
217
217
|
# Possibilities: Unslicable object (TypeError) or Wrong dimensions or out of range (IndexError)
|
218
218
|
raise type(e)(str(e) + "\n\t| Above error was raised in SignalSlice.state (setter). Signal details:" +
|
@@ -221,7 +221,7 @@ class SignalSlice(Signal):
|
|
221
221
|
@property
|
222
222
|
def sensitivity(self):
|
223
223
|
try:
|
224
|
-
return None if self.
|
224
|
+
return None if self.base.sensitivity is None else self.base.sensitivity[self.slice]
|
225
225
|
except Exception as e:
|
226
226
|
# Possibilities: Unslicable object (TypeError) or Wrong dimensions or out of range (IndexError)
|
227
227
|
raise type(e)(str(e) + "\n\t| Above error was raised in SignalSlice.sensitivity (getter). Signal details:" +
|
@@ -230,26 +230,55 @@ class SignalSlice(Signal):
|
|
230
230
|
@sensitivity.setter
|
231
231
|
def sensitivity(self, new_sens):
|
232
232
|
try:
|
233
|
-
if self.
|
233
|
+
if self.base.sensitivity is None:
|
234
|
+
# Initialize sensitivity of base-signal
|
234
235
|
if new_sens is None:
|
235
236
|
return # Sensitivity doesn't need to be initialized when it is set to None
|
236
237
|
try:
|
237
|
-
self.
|
238
|
+
self.base.sensitivity = self.base.state * 0 # Make a new copy with 0 values
|
238
239
|
except TypeError:
|
239
|
-
if self.
|
240
|
+
if self.base.state is None:
|
240
241
|
raise TypeError("Could not initialize sensitivity because state is not set" + self._err_str())
|
241
242
|
else:
|
242
|
-
raise TypeError(f"Could not initialize sensitivity for type \'{type(self.
|
243
|
+
raise TypeError(f"Could not initialize sensitivity for type \'{type(self.base.state).__name__}\'")
|
243
244
|
|
244
245
|
if new_sens is None:
|
245
246
|
new_sens = 0 # reset() uses this
|
246
247
|
|
247
|
-
self.
|
248
|
+
self.base.sensitivity[self.slice] = new_sens
|
248
249
|
except Exception as e:
|
249
250
|
# Possibilities: Unslicable object (TypeError) or Wrong dimensions or out of range (IndexError)
|
250
251
|
raise type(e)(str(e) + "\n\t| Above error was raised in SignalSlice.state (setter). Signal details:" +
|
251
252
|
self._err_str()).with_traceback(sys.exc_info()[2])
|
252
253
|
|
254
|
+
def add_sensitivity(self, ds: Any):
|
255
|
+
""" Add a new term to internal sensitivity """
|
256
|
+
try:
|
257
|
+
if ds is None:
|
258
|
+
return
|
259
|
+
if self.base.sensitivity is None:
|
260
|
+
self.base.sensitivity = self.base.state * 0
|
261
|
+
# self.sensitivity = copy.deepcopy(ds)
|
262
|
+
|
263
|
+
if hasattr(self.sensitivity, "add_sensitivity"):
|
264
|
+
# Allow user to implement a custom add_sensitivity function instead of __iadd__
|
265
|
+
self.sensitivity.add_sensitivity(ds)
|
266
|
+
else:
|
267
|
+
self.sensitivity += ds
|
268
|
+
return self
|
269
|
+
except TypeError:
|
270
|
+
if isinstance(ds, type(self.sensitivity)):
|
271
|
+
raise TypeError(
|
272
|
+
f"Cannot add to the sensitivity with type '{type(self.sensitivity).__name__}'" + self._err_str())
|
273
|
+
else:
|
274
|
+
raise TypeError(
|
275
|
+
f"Adding wrong type '{type(ds).__name__}' to the sensitivity '{type(self.sensitivity).__name__}'" + self._err_str())
|
276
|
+
except ValueError:
|
277
|
+
sens_shape = self.sensitivity.shape if hasattr(self.sensitivity, 'shape') else ()
|
278
|
+
ds_shape = ds.shape if hasattr(ds, 'shape') else ()
|
279
|
+
raise ValueError(
|
280
|
+
f"Cannot add argument of shape {ds_shape} to the sensitivity of shape {sens_shape}" + self._err_str()) from None
|
281
|
+
|
253
282
|
def reset(self, keep_alloc: bool = None):
|
254
283
|
""" Reset the sensitivities to zero or None
|
255
284
|
This must be called to clear internal memory of subsequent sensitivity calculations.
|
@@ -408,7 +437,7 @@ class Module(ABC, RegisteredClass):
|
|
408
437
|
>> Module([inputs])
|
409
438
|
|
410
439
|
Using keywords:
|
411
|
-
>> Module(sig_in=[inputs], sig_out=[outputs]
|
440
|
+
>> Module(sig_in=[inputs], sig_out=[outputs])
|
412
441
|
"""
|
413
442
|
|
414
443
|
def _err_str(self, module_signature: bool = True, init: bool = True, fn=None):
|
@@ -556,67 +585,74 @@ class Module(ABC, RegisteredClass):
|
|
556
585
|
class Network(Module):
|
557
586
|
""" Binds multiple Modules together as one Module
|
558
587
|
|
588
|
+
Initialize a network with a number of modules that should be executed consecutively
|
559
589
|
>> Network(module1, module2, ...)
|
560
590
|
|
561
591
|
>> Network([module1, module2, ...])
|
562
592
|
|
563
593
|
>> Network((module1, module2, ...))
|
564
594
|
|
595
|
+
Modules can also be constructed using a dictionary based on strings
|
565
596
|
>> Network([ {type="module1", sig_in=[sig1, sig2], sig_out=[sig3]},
|
566
597
|
{type="module2", sig_in=[sig3], sig_out=[sig4]} ])
|
567
598
|
|
599
|
+
Appending modules to a network will output the signals automatically
|
600
|
+
>> fn = Network()
|
601
|
+
>> s_out = fn.append(module1)
|
602
|
+
|
603
|
+
Args:
|
604
|
+
print_timing: Print timing of each module inside this Network
|
568
605
|
"""
|
569
606
|
def __init__(self, *args, print_timing=False):
|
607
|
+
super().__init__()
|
570
608
|
self._init_loc = get_init_str()
|
571
|
-
|
572
|
-
#
|
573
|
-
self.mods = _parse_to_list(*args)
|
574
|
-
|
575
|
-
# Check if the blocks are initialized, else create them
|
576
|
-
for i, b in enumerate(self.mods):
|
577
|
-
if isinstance(b, dict):
|
578
|
-
exclude_keys = ['type']
|
579
|
-
b_ex = {k: b[k] for k in set(list(b.keys())) - set(exclude_keys)}
|
580
|
-
self.mods[i] = Module.create(b['type'], **b_ex)
|
581
|
-
|
582
|
-
# Check validity of modules
|
583
|
-
for m in self.mods:
|
584
|
-
if not _is_valid_module(m):
|
585
|
-
raise TypeError(f"Argument is not a valid Module, type=\'{type(mod).__name__}\'.")
|
586
|
-
|
587
|
-
# Gather all the input and output signals of the internal blocks
|
588
|
-
all_in = set()
|
589
|
-
all_out = set()
|
590
|
-
[all_in.update(b.sig_in) for b in self.mods]
|
591
|
-
[all_out.update(b.sig_out) for b in self.mods]
|
592
|
-
in_unique = all_in - all_out
|
593
|
-
|
594
|
-
# Initialize the parent module, with correct inputs and outputs
|
595
|
-
super().__init__(list(in_unique), list(all_out))
|
596
|
-
|
609
|
+
self.mods = [] # Empty module list
|
610
|
+
self.append(*args) # Append to module list
|
597
611
|
self.print_timing = print_timing
|
598
612
|
|
599
|
-
def timefn(self, fn,
|
613
|
+
def timefn(self, fn, name=None):
|
600
614
|
start_t = time.time()
|
601
615
|
fn()
|
602
616
|
duration = time.time() - start_t
|
603
|
-
if
|
604
|
-
|
617
|
+
if name is None:
|
618
|
+
name = f"{fn}"
|
619
|
+
if isinstance(self.print_timing, bool):
|
620
|
+
tmin = 0.0
|
621
|
+
else:
|
622
|
+
tmin = self.print_timing
|
623
|
+
if duration > tmin:
|
624
|
+
print(f"{name} took {time.time() - start_t} s")
|
605
625
|
|
606
626
|
def response(self):
|
607
|
-
if self.print_timing:
|
608
|
-
|
627
|
+
if self.print_timing is not False:
|
628
|
+
start_t = time.time()
|
629
|
+
[self.timefn(m.response, name=f"-- Response of \"{type(m).__name__}\"") for m in self.mods]
|
630
|
+
duration = time.time() - start_t
|
631
|
+
if isinstance(self.print_timing, bool):
|
632
|
+
tmin = 0.0
|
633
|
+
else:
|
634
|
+
tmin = self.print_timing
|
635
|
+
if duration > tmin:
|
636
|
+
print(f"-- TOTAL Response took {time.time() - start_t} s")
|
609
637
|
else:
|
610
|
-
[
|
638
|
+
[m.response() for m in self.mods]
|
611
639
|
|
612
640
|
def sensitivity(self):
|
613
|
-
if self.print_timing:
|
614
|
-
|
641
|
+
if self.print_timing is not False:
|
642
|
+
start_t = time.time()
|
643
|
+
[self.timefn(m.sensitivity, name=f"-- Sensitivity of \"{type(m).__name__}\"") for m in reversed(self.mods)]
|
644
|
+
duration = time.time() - start_t
|
645
|
+
if isinstance(self.print_timing, bool):
|
646
|
+
tmin = 0.0
|
647
|
+
else:
|
648
|
+
tmin = self.print_timing
|
649
|
+
if duration > tmin:
|
650
|
+
print(f"-- TOTAL Sensitivity took {time.time() - start_t} s")
|
615
651
|
else:
|
616
|
-
[
|
652
|
+
[m.sensitivity() for m in reversed(self.mods)]
|
617
653
|
|
618
654
|
def reset(self):
|
619
|
-
[
|
655
|
+
[m.reset() for m in reversed(self.mods)]
|
620
656
|
|
621
657
|
def _response(self, *args):
|
622
658
|
pass # Unused
|
@@ -636,13 +672,25 @@ class Network(Module):
|
|
636
672
|
def __iter__(self):
|
637
673
|
return iter(self.mods)
|
638
674
|
|
675
|
+
def __call__(self, *args):
|
676
|
+
return self.append(*args)
|
677
|
+
|
639
678
|
def append(self, *newmods):
|
640
679
|
modlist = _parse_to_list(*newmods)
|
680
|
+
if len(modlist) == 0:
|
681
|
+
return
|
641
682
|
|
642
683
|
# Check if the blocks are initialized, else create them
|
684
|
+
for i, m in enumerate(modlist):
|
685
|
+
if isinstance(m, dict):
|
686
|
+
exclude_keys = ['type']
|
687
|
+
b_ex = {k: m[k] for k in set(list(m.keys())) - set(exclude_keys)}
|
688
|
+
modlist[i] = Module.create(m['type'], **b_ex)
|
689
|
+
|
690
|
+
# Check validity of modules
|
643
691
|
for i, m in enumerate(modlist):
|
644
692
|
if not _is_valid_module(m):
|
645
|
-
raise TypeError(f"Argument #{i} is not a valid module, type=\'{type(
|
693
|
+
raise TypeError(f"Argument #{i} is not a valid module, type=\'{type(m).__name__}\'.")
|
646
694
|
|
647
695
|
# Obtain the internal blocks
|
648
696
|
self.mods.extend(modlist)
|
@@ -657,4 +705,4 @@ class Network(Module):
|
|
657
705
|
self.sig_in = _parse_to_list(in_unique)
|
658
706
|
self.sig_out = _parse_to_list(all_out)
|
659
707
|
|
660
|
-
return modlist[-1].sig_out[0] if len(modlist[-1].sig_out) == 1 else modlist[-1].sig_out
|
708
|
+
return modlist[-1].sig_out[0] if len(modlist[-1].sig_out) == 1 else modlist[-1].sig_out
|
pymoto/modules/assembly.py
CHANGED
@@ -57,20 +57,21 @@ class AssembleGeneral(Module):
|
|
57
57
|
self.bc = bc
|
58
58
|
self.bcdiagval = np.max(element_matrix) if bcdiagval is None else bcdiagval
|
59
59
|
if bc is not None:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
self.
|
64
|
-
self.cols = np.concatenate((self.cols[self.bcselect], self.bc))
|
60
|
+
bc_inds = np.bitwise_or(np.isin(self.rows, self.bc), np.isin(self.cols, self.bc))
|
61
|
+
self.bcselect = np.argwhere(np.bitwise_not(bc_inds)).flatten()
|
62
|
+
self.bcrows = np.concatenate((self.rows[self.bcselect], self.bc))
|
63
|
+
self.bccols = np.concatenate((self.cols[self.bcselect], self.bc))
|
65
64
|
else:
|
66
65
|
self.bcselect = None
|
66
|
+
self.bcrows = self.rows
|
67
|
+
self.bccols = self.cols
|
67
68
|
|
68
69
|
self.add_constant = add_constant
|
69
70
|
|
70
71
|
def _response(self, xscale: np.ndarray):
|
71
72
|
nel = self.dofconn.shape[0]
|
72
73
|
assert xscale.size == nel, f"Input vector wrong size ({xscale.size}), must be of size #nel ({nel})"
|
73
|
-
scaled_el = (
|
74
|
+
scaled_el = (self.elmat.flatten() * xscale[..., np.newaxis]).flatten()
|
74
75
|
|
75
76
|
# Set boundary conditions
|
76
77
|
if self.bc is not None:
|
@@ -80,7 +81,7 @@ class AssembleGeneral(Module):
|
|
80
81
|
mat_values = scaled_el
|
81
82
|
|
82
83
|
try:
|
83
|
-
mat = self.matrix_type((mat_values, (self.
|
84
|
+
mat = self.matrix_type((mat_values, (self.bcrows, self.bccols)), shape=(self.n, self.n))
|
84
85
|
except TypeError as e:
|
85
86
|
raise type(e)(str(e) + "\n\tInvalid matrix_type={}. Either scipy.sparse.cscmatrix or "
|
86
87
|
"scipy.sparse.csrmatrix are supported"
|
@@ -96,14 +97,16 @@ class AssembleGeneral(Module):
|
|
96
97
|
if self.bc is not None:
|
97
98
|
dgdmat[self.bc, :] = 0.0
|
98
99
|
dgdmat[:, self.bc] = 0.0
|
100
|
+
dx = np.zeros_like(self.sig_in[0].state)
|
99
101
|
if isinstance(dgdmat, np.ndarray):
|
100
|
-
dx = np.zeros_like(self.sig_in[0].state)
|
101
102
|
for i in range(len(dx)):
|
102
103
|
indu, indv = np.meshgrid(self.dofconn[i], self.dofconn[i], indexing='ij')
|
103
|
-
|
104
|
-
|
104
|
+
dxi = einsum("ij,ij->", self.elmat, dgdmat[indu, indv])
|
105
|
+
dx[i] = np.real(dxi) if np.isrealobj(dx) else dxi
|
105
106
|
elif isinstance(dgdmat, DyadCarrier):
|
106
|
-
|
107
|
+
dxi = dgdmat.contract(self.elmat, self.dofconn, self.dofconn)
|
108
|
+
dx[:] = np.real(dxi) if np.isrealobj(dx) else dxi
|
109
|
+
return dx
|
107
110
|
|
108
111
|
|
109
112
|
def get_B(dN_dx, voigt=True):
|
@@ -123,7 +126,7 @@ def get_B(dN_dx, voigt=True):
|
|
123
126
|
"""
|
124
127
|
n_dim, n_shapefn = dN_dx.shape
|
125
128
|
n_strains = int((n_dim * (n_dim+1))/2) # Triangular number: ndim=3 -> nstrains = 3+2+1
|
126
|
-
B = np.zeros((n_strains, n_shapefn*n_dim))
|
129
|
+
B = np.zeros((n_strains, n_shapefn*n_dim), dtype=dN_dx.dtype)
|
127
130
|
if n_dim == 1:
|
128
131
|
for i in range(n_shapefn):
|
129
132
|
B[i, 0] = dN_dx[i, 0]
|
@@ -222,7 +225,8 @@ class AssembleStiffness(AssembleGeneral):
|
|
222
225
|
ndof = nnode*domain.dim
|
223
226
|
|
224
227
|
# Element stiffness matrix
|
225
|
-
|
228
|
+
dtype = np.result_type(D, domain.element_size.dtype)
|
229
|
+
self.stiffness_element = np.zeros((ndof, ndof), dtype=dtype)
|
226
230
|
|
227
231
|
# Numerical integration
|
228
232
|
siz = domain.element_size
|
pymoto/modules/io.py
CHANGED
@@ -202,15 +202,16 @@ class PlotIter(FigModule):
|
|
202
202
|
show (bool): Show the figure on the screen
|
203
203
|
ylim: Provide y-axis limits for the plot
|
204
204
|
"""
|
205
|
-
def _prepare(self, ylim=None):
|
205
|
+
def _prepare(self, ylim=None, log_scale=False):
|
206
206
|
self.minlim = 1e+200
|
207
207
|
self.maxlim = -1e+200
|
208
208
|
self.ylim = ylim
|
209
|
+
self.log_scale = log_scale
|
209
210
|
|
210
211
|
def _response(self, *args):
|
211
212
|
if not hasattr(self, 'ax'):
|
212
213
|
self.ax = self.fig.add_subplot(111)
|
213
|
-
self.ax.set_yscale('linear')
|
214
|
+
self.ax.set_yscale('linear' if not self.log_scale else 'log')
|
214
215
|
self.ax.set_xlabel("Iteration")
|
215
216
|
|
216
217
|
if not hasattr(self, 'line'):
|
@@ -233,13 +234,24 @@ class PlotIter(FigModule):
|
|
233
234
|
self.minlim = min(self.minlim, np.min(xadd))
|
234
235
|
self.maxlim = max(self.maxlim, np.max(xadd))
|
235
236
|
|
236
|
-
dy = max((self.maxlim - self.minlim)*0.05, sys.float_info.min)
|
237
|
-
|
238
237
|
self.ax.set_xlim([-0.5, self.iter+0.5])
|
239
238
|
if self.ylim is not None:
|
240
239
|
self.ax.set_ylim(self.ylim)
|
241
240
|
elif np.isfinite(self.minlim) and np.isfinite(self.maxlim):
|
242
|
-
|
241
|
+
if self.log_scale:
|
242
|
+
dy = (np.log10(self.maxlim) - np.log10(self.minlim))*0.05
|
243
|
+
ll = 10**(np.log10(self.minlim) - dy)
|
244
|
+
ul = 10**(np.log10(self.maxlim) + dy)
|
245
|
+
else:
|
246
|
+
dy = (self.maxlim - self.minlim)*0.05
|
247
|
+
ll = self.minlim - dy
|
248
|
+
ul = self.maxlim + dy
|
249
|
+
|
250
|
+
if ll == ul:
|
251
|
+
dy = abs(np.nextafter(abs(ll), 1) - abs(ll))
|
252
|
+
ll = ll - 1e5*dy
|
253
|
+
ul = ul + 1e5*dy
|
254
|
+
self.ax.set_ylim([ll, ul])
|
243
255
|
|
244
256
|
self._update_fig()
|
245
257
|
|
pymoto/modules/linalg.py
CHANGED
@@ -268,7 +268,7 @@ class LinSolve(Module):
|
|
268
268
|
if not isinstance(self.solver, LDAWrapper) and self.use_lda_solver:
|
269
269
|
lda_kwargs = dict(hermitian=self.ishermitian, symmetric=self.issymmetric)
|
270
270
|
if hasattr(self.solver, 'tol'):
|
271
|
-
lda_kwargs['tol'] = self.solver.tol *
|
271
|
+
lda_kwargs['tol'] = self.solver.tol * 5
|
272
272
|
self.solver = LDAWrapper(self.solver, **lda_kwargs)
|
273
273
|
|
274
274
|
# Update solver with new matrix
|
@@ -371,9 +371,11 @@ class EigenSolve(Module):
|
|
371
371
|
Bqi = qi if B is None else B@qi
|
372
372
|
|
373
373
|
normval = np.sqrt(qi @ Bqi)
|
374
|
-
|
375
|
-
|
376
|
-
|
374
|
+
sgn = 1 if np.real(np.average(qi)) >= 0 else -1
|
375
|
+
sf = sgn / normval
|
376
|
+
assert np.isfinite(sf)
|
377
|
+
if sf == 0.0:
|
378
|
+
warnings.warn(f"Scaling factor of mode {i} is zero!")
|
377
379
|
qi *= sf
|
378
380
|
return W, Q
|
379
381
|
|
@@ -423,8 +425,9 @@ class EigenSolve(Module):
|
|
423
425
|
if self.is_hermitian:
|
424
426
|
return spsla.eigsh(A, M=B, k=self.nmodes, OPinv=AinvOp, sigma=self.sigma, mode=self.mode)
|
425
427
|
else:
|
426
|
-
|
427
|
-
|
428
|
+
if self.mode.lower() not in ['normal']:
|
429
|
+
raise NotImplementedError('Only `normal` mode can be selected for non-hermitian matrix')
|
430
|
+
return spsla.eigs(A, M=B, k=self.nmodes, OPinv=AinvOp, sigma=self.sigma)
|
428
431
|
|
429
432
|
def _dense_sens(self, A, B, dW, dQ):
|
430
433
|
""" Calculates all (eigenvector and eigenvalue) sensitivities for dense matrix """
|
@@ -465,17 +468,14 @@ class EigenSolve(Module):
|
|
465
468
|
qi = Q[:, i]
|
466
469
|
qmq = qi@qi if B is None else qi @ (B @ qi)
|
467
470
|
dA_u = (dwi/qmq) * qi
|
468
|
-
|
469
|
-
|
470
|
-
else:
|
471
|
-
dA += DyadCarrier(dA_u, qi)
|
471
|
+
dAi = DyadCarrier(dA_u, qi)
|
472
|
+
dA += np.real(dAi) if np.isrealobj(A) else dAi
|
472
473
|
|
473
474
|
if dB is not None:
|
474
475
|
dB_u = (wi*dwi/qmq) * qi
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
dB -= DyadCarrier(dB_u, qi)
|
476
|
+
dBi = DyadCarrier(dB_u, qi)
|
477
|
+
dB -= np.real(dBi) if np.isrealobj(B) else dBi
|
478
|
+
|
479
479
|
return dA, dB
|
480
480
|
|
481
481
|
def _sparse_eigvec_sens(self, A, B, dW, dQ):
|
pymoto/routines.py
CHANGED
@@ -10,10 +10,10 @@ from scipy.sparse import issparse
|
|
10
10
|
def _has_signal_overlap(sig1: List[Signal], sig2: List[Signal]):
|
11
11
|
for s1 in sig1:
|
12
12
|
while isinstance(s1, SignalSlice):
|
13
|
-
s1 = s1.
|
13
|
+
s1 = s1.base
|
14
14
|
for s2 in sig2:
|
15
15
|
while isinstance(s2, SignalSlice):
|
16
|
-
s2 = s2.
|
16
|
+
s2 = s2.base
|
17
17
|
if s1 == s2:
|
18
18
|
return True
|
19
19
|
return False
|
pymoto/solvers/iterative.py
CHANGED
@@ -132,7 +132,7 @@ class GeometricMultigrid(Preconditioner):
|
|
132
132
|
assert cycle.lower() in self._available_cycles, f"Cycle ({cycle}) is not available. Options are {self._available_cycles}"
|
133
133
|
self.cycle = cycle
|
134
134
|
self.inner_level = None if inner_level is None else inner_level
|
135
|
-
self.smoother = DampedJacobi(w=0.5) if smoother is None else
|
135
|
+
self.smoother = DampedJacobi(w=0.5) if smoother is None else smoother
|
136
136
|
self.smooth_steps = smooth_steps
|
137
137
|
self.R = None
|
138
138
|
self.sub_domain = DomainDefinition(domain.nelx // 2, domain.nely // 2, domain.nelz // 2,
|
@@ -299,7 +299,7 @@ class CG(LinearSolver):
|
|
299
299
|
self.A = A
|
300
300
|
self.preconditioner.update(A)
|
301
301
|
if self.verbosity >= 1:
|
302
|
-
print(f"Preconditioner set up in {np.round(time.perf_counter() - tstart,3)}s")
|
302
|
+
print(f"CG Preconditioner set up in {np.round(time.perf_counter() - tstart, 3)}s")
|
303
303
|
|
304
304
|
def solve(self, rhs, x0=None, trans='N'):
|
305
305
|
if trans == 'N':
|
@@ -321,10 +321,18 @@ class CG(LinearSolver):
|
|
321
321
|
x = x.reshape((x.size, 1))
|
322
322
|
|
323
323
|
r = b - A@x
|
324
|
+
tval = np.linalg.norm(r, axis=0) / np.linalg.norm(b, axis=0)
|
325
|
+
if self.verbosity >= 2:
|
326
|
+
print(f"CG Initial (max) residual = {tval.max()}")
|
327
|
+
|
328
|
+
if tval.max() <= self.tol:
|
329
|
+
if self.verbosity >= 1:
|
330
|
+
print(f"CG Converged in 0 iterations and {np.round(time.perf_counter() - tstart, 3)}s, with final (max) residual {tval.max()}")
|
331
|
+
|
332
|
+
return x.flatten() if rhs.ndim == 1 else x
|
333
|
+
|
324
334
|
z = self.preconditioner.solve(r, trans=trans)
|
325
335
|
p = orth(z, normalize=True)
|
326
|
-
if self.verbosity >= 2:
|
327
|
-
print(f"Initial residual = {np.linalg.norm(r, axis=0) / np.linalg.norm(b, axis=0)}")
|
328
336
|
|
329
337
|
for i in range(self.maxit):
|
330
338
|
q = A @ p
|
@@ -333,16 +341,15 @@ class CG(LinearSolver):
|
|
333
341
|
alpha = pq_inv @ (p.conj().T @ r)
|
334
342
|
|
335
343
|
x += p @ alpha
|
336
|
-
if i %
|
344
|
+
if i % self.restart == 0: # Explicit restart
|
337
345
|
r = b - A@x
|
338
346
|
else:
|
339
347
|
r -= q @ alpha
|
340
348
|
|
349
|
+
tval = np.linalg.norm(r, axis=0)/np.linalg.norm(b, axis=0)
|
341
350
|
if self.verbosity >= 2:
|
342
|
-
print(f"i = {i}, residuals = {
|
343
|
-
|
344
|
-
tval = np.linalg.norm(r)/np.linalg.norm(b)
|
345
|
-
if tval <= self.tol:
|
351
|
+
print(f"CG i = {i}, residuals = {tval}")
|
352
|
+
if tval.max() <= self.tol:
|
346
353
|
break
|
347
354
|
|
348
355
|
z = self.preconditioner.solve(r, trans=trans)
|
@@ -350,12 +357,9 @@ class CG(LinearSolver):
|
|
350
357
|
beta = -pq_inv @ (q.conj().T @ z)
|
351
358
|
p = orth(z + p@beta, normalize=False)
|
352
359
|
|
353
|
-
if tval > self.tol:
|
354
|
-
warnings.warn(f'Maximum iterations ({self.maxit}) reached, with final
|
360
|
+
if tval.max() > self.tol:
|
361
|
+
warnings.warn(f'CG Maximum iterations ({self.maxit}) reached, with final residuals {tval}')
|
355
362
|
elif self.verbosity >= 1:
|
356
|
-
print(f"Converged in {i} iterations and {np.round(time.perf_counter() - tstart, 3)}s, with final
|
363
|
+
print(f"CG Converged in {i} iterations and {np.round(time.perf_counter() - tstart, 3)}s, with final (max) residual {tval.max()}")
|
357
364
|
|
358
|
-
if rhs.ndim == 1
|
359
|
-
return x.flatten()
|
360
|
-
else:
|
361
|
-
return x
|
365
|
+
return x.flatten() if rhs.ndim == 1 else x
|
pymoto/solvers/solvers.py
CHANGED
@@ -75,6 +75,17 @@ class LinearSolver:
|
|
75
75
|
return np.linalg.norm(mat@x - b, axis=0) / np.linalg.norm(b, axis=0)
|
76
76
|
|
77
77
|
|
78
|
+
def get_diagonal_indices(mat):
|
79
|
+
""" Get the row/column indices for entries in the matrix that are diagonal (has all zeros in its row and column) """
|
80
|
+
assert mat.ndim == 2, "Not a matrix"
|
81
|
+
n = min(*mat.shape) # Matrix size
|
82
|
+
bmat = mat != 0
|
83
|
+
has_diag = bmat.diagonal()
|
84
|
+
nnz_rows = np.array(bmat.sum(axis=0)).flatten()[:n]
|
85
|
+
nnz_cols = np.array(bmat.sum(axis=1)).flatten()[:n]
|
86
|
+
return np.logical_and(has_diag, nnz_rows <= 1, nnz_cols <= 1)
|
87
|
+
|
88
|
+
|
78
89
|
class LDAWrapper(LinearSolver):
|
79
90
|
r""" Linear dependency aware solver (LDAS)
|
80
91
|
|
@@ -105,6 +116,8 @@ class LDAWrapper(LinearSolver):
|
|
105
116
|
self.xadj_stored = []
|
106
117
|
self.badj_stored = []
|
107
118
|
self.A = None
|
119
|
+
self.diagonal_idx = []
|
120
|
+
self.nondiagonal_idx = slice(None)
|
108
121
|
self._did_solve = False # For debugging purposes
|
109
122
|
self._last_rtol = 0.
|
110
123
|
self.hermitian = hermitian
|
@@ -123,6 +136,9 @@ class LDAWrapper(LinearSolver):
|
|
123
136
|
self.hermitian = matrix_is_hermitian(A)
|
124
137
|
|
125
138
|
self.A = A
|
139
|
+
diags = get_diagonal_indices(A)
|
140
|
+
self.diagonal_idx = np.argwhere(diags).flatten()
|
141
|
+
self.nondiagonal_idx = np.argwhere(~diags).flatten()
|
126
142
|
self.x_stored.clear()
|
127
143
|
self.b_stored.clear()
|
128
144
|
self.xadj_stored.clear()
|
@@ -130,6 +146,9 @@ class LDAWrapper(LinearSolver):
|
|
130
146
|
self.solver.update(A)
|
131
147
|
|
132
148
|
def _do_solve_1rhs(self, A, rhs, x_data, b_data, solve_fn, x0=None):
|
149
|
+
isel = self.nondiagonal_idx
|
150
|
+
idia = self.diagonal_idx
|
151
|
+
|
133
152
|
dtype = np.result_type(A, rhs)
|
134
153
|
if rhs.ndim == 1:
|
135
154
|
rhs_loc = np.zeros((rhs.size, 1), dtype=dtype)
|
@@ -139,11 +158,16 @@ class LDAWrapper(LinearSolver):
|
|
139
158
|
rhs_loc[:] = rhs
|
140
159
|
sol = np.zeros_like(rhs_loc, dtype=dtype)
|
141
160
|
|
142
|
-
#
|
161
|
+
# Diagonal part of the matrix
|
162
|
+
sol[idia, ...] = rhs_loc[idia, ...] / A.diagonal()[idia, None]
|
163
|
+
rhs_loc[idia, ...] = 0
|
164
|
+
|
165
|
+
# Non-diagonal part of the matrix
|
166
|
+
# Reconstruct using the database using modified Gram-Schmidt
|
143
167
|
for (x, b) in zip(x_data, b_data):
|
144
168
|
assert x.ndim == b.ndim == 1
|
145
|
-
assert x.size == b.size == rhs_loc.shape[0]
|
146
|
-
alpha = rhs_loc.T @ b.conj() / (b.conj() @ b)
|
169
|
+
# assert x.size == b.size == rhs_loc.shape[0]
|
170
|
+
alpha = rhs_loc[isel, ...].T @ b.conj() / (b.conj() @ b)
|
147
171
|
|
148
172
|
rem_rhs = alpha * b[:, None]
|
149
173
|
add_sol = alpha * x[:, None]
|
@@ -162,34 +186,41 @@ class LDAWrapper(LinearSolver):
|
|
162
186
|
warnings.warn('LDAS: Complex vector cannot be added to real solution')
|
163
187
|
continue
|
164
188
|
|
165
|
-
rhs_loc -= rem_rhs
|
166
|
-
sol += add_sol
|
189
|
+
rhs_loc[isel, ...] -= rem_rhs
|
190
|
+
sol[isel, ...] += add_sol
|
191
|
+
|
192
|
+
assert np.all(rhs_loc[idia, ...] == 0)
|
167
193
|
|
168
194
|
# Check tolerance
|
169
|
-
self._last_rtol =
|
195
|
+
self._last_rtol = self.residual(A, sol, rhs if rhs.ndim > 1 else rhs.reshape(-1, 1))
|
170
196
|
self._did_solve = self._last_rtol > self.tol
|
197
|
+
# If tolerance too large, use the solver for new values
|
171
198
|
if np.any(self._did_solve):
|
172
199
|
if x0 is not None:
|
173
200
|
if x0.ndim == 1:
|
174
201
|
x0_loc = x0.reshape(-1, 1).copy()
|
175
202
|
else:
|
176
203
|
x0_loc = x0[..., self._did_solve].copy()
|
204
|
+
x0_loc[idia, ...] = 0
|
177
205
|
for x in x_data:
|
178
|
-
beta = x0_loc.T @ x.conj() / (x.conj() @ x)
|
179
|
-
x0_loc -= beta * x
|
206
|
+
beta = x0_loc[isel, ...].T @ x.conj() / (x.conj() @ x)
|
207
|
+
x0_loc[isel, ...] -= beta * x
|
180
208
|
else:
|
181
209
|
x0_loc = None
|
182
210
|
|
183
|
-
# Calculate a new solution
|
211
|
+
# Calculate a new solution (for the vectors that have too high residual)
|
184
212
|
xnew = solve_fn(rhs_loc[..., self._did_solve], x0_loc)
|
185
|
-
|
186
|
-
|
213
|
+
|
214
|
+
if isinstance(isel, slice):
|
215
|
+
sol[isel, self._did_solve] += xnew[isel, ...]
|
216
|
+
else:
|
217
|
+
sol[np.ix_(isel, self._did_solve)] += xnew[isel, ...]
|
187
218
|
|
188
219
|
# Add to database
|
189
220
|
for i in range(xnew.shape[-1]):
|
190
221
|
# Remove all previous components that are already in the database (orthogonalize)
|
191
|
-
xadd = xnew[
|
192
|
-
badd = A @
|
222
|
+
xadd = xnew[isel, i]
|
223
|
+
badd = (A @ xnew[..., i])[isel, ...]
|
193
224
|
for x, b in zip(x_data, b_data):
|
194
225
|
beta = badd @ b.conj() / (b.conj() @ b)
|
195
226
|
badd -= beta * b
|
pymoto/solvers/sparse.py
CHANGED
@@ -140,6 +140,9 @@ class SolverSparsePardiso(LinearSolver):
|
|
140
140
|
Returns:
|
141
141
|
Solution of the system of linear equations, same shape as input b
|
142
142
|
"""
|
143
|
+
if b.dtype != np.float64: # Only float64 is supported --> this is also done in _check_b, but fails for int8
|
144
|
+
warnings.warn(f"Array b's data type was converted from {b.dtype} to float64")
|
145
|
+
b = b.astype(np.float64)
|
143
146
|
if trans == 'N':
|
144
147
|
return self._pardiso_solver.solve(self.A, b)
|
145
148
|
elif trans == 'T' or trans == 'H':
|
@@ -200,6 +203,13 @@ class SolverSparsePardiso(LinearSolver):
|
|
200
203
|
if v != 0:
|
201
204
|
print(f"{i+1}: {v} ({k})") # i+1 because of 1-based numbering
|
202
205
|
|
206
|
+
def __del__(self):
|
207
|
+
try:
|
208
|
+
self._pardiso_solver.free_memory(everything=True)
|
209
|
+
except ImportError:
|
210
|
+
# To prevent ImportError: sys.meta_path is None, Python is likely shutting down
|
211
|
+
pass
|
212
|
+
|
203
213
|
|
204
214
|
# ------------------------------------ LU Solver -----------------------------------
|
205
215
|
try:
|
pyMOTO-1.5.0.dist-info/RECORD
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
pymoto/__init__.py,sha256=YLMAiO2PZHAC6nYWXVh03rhZnZkc_Rc2z7SGQj1T8I4,2058
|
2
|
-
pymoto/core_objects.py,sha256=88AOo041wrcRSPoLCRwBXUoYANGX-b2SAA0Nuf6sn2Y,25252
|
3
|
-
pymoto/routines.py,sha256=yjvcQDcWU47ZM6ZpZoX8VwrJoN9JDO_25DSa9oVcKec,15582
|
4
|
-
pymoto/utils.py,sha256=YJ-PNLJLc12Yx6TYCrEechS2aaBRx0o4mTM1soeeyz0,1122
|
5
|
-
pymoto/common/domain.py,sha256=-eFuYRLehQ17Ai-cV59f4I9FbEM-DJAj6kjjVfj31X0,18120
|
6
|
-
pymoto/common/dyadcarrier.py,sha256=VwMbqPr0NMDPfpsH0BwvXp8M1dmh8ijFDpF6yoyTmto,19394
|
7
|
-
pymoto/common/mma.py,sha256=Pof3clOHA8PG51TmUjs11dkjSP96kovZjsPv62tI2Ec,24055
|
8
|
-
pymoto/modules/aggregation.py,sha256=Oi17hIJ6dic4lOPw16zmjbdC72MjB6XK34H80bnbWAI,7580
|
9
|
-
pymoto/modules/assembly.py,sha256=quuR8QpB2w-O0zly-xS6PK6wZQMY6S5TWh15Y9wuh14,22974
|
10
|
-
pymoto/modules/autodiff.py,sha256=WAfoAOHBSozf7jbr9gQz9Vw4a_2G9wGJxLMMqUQP0Co,1684
|
11
|
-
pymoto/modules/complex.py,sha256=B_Obk-ABdV66lEudZ5s8o6qG9NsmYlBsX-PbWvbphhc,4429
|
12
|
-
pymoto/modules/filter.py,sha256=6X9FaQMWYZ_TpHVTFiEibzlmAwmSWbydYM93LFrJ0Wo,25490
|
13
|
-
pymoto/modules/generic.py,sha256=YzsGZ8J0oLCORt78Bf2p0v4GuqpWRI77NLoCk7gqidw,10666
|
14
|
-
pymoto/modules/io.py,sha256=LcFvJ-cPgg5ee-aag8kaxHw5RzQ-ggxOM5jk7PeJ1r8,13140
|
15
|
-
pymoto/modules/linalg.py,sha256=BNkih4nvvkYuQpm4bG5U38dAjkfD5EFi3MjANpBEPPI,21927
|
16
|
-
pymoto/modules/scaling.py,sha256=uq88HHW9rP16XLz7UGc3CNBBpY2Z1glo8yjYxZEnXUg,2327
|
17
|
-
pymoto/solvers/__init__.py,sha256=9JUeD2SgZbkYFullA7s7s6SuAVv0onqAqJ8hFvNOs2g,1033
|
18
|
-
pymoto/solvers/auto_determine.py,sha256=X8MEG7h6jLfAV1inpja45_-suG8qQFMfLMDfW2ryQqQ,5134
|
19
|
-
pymoto/solvers/dense.py,sha256=9fKPCwNxRKAEk5k1A7fdLrr9ngeVssGlw-sbjWCm4iU,11235
|
20
|
-
pymoto/solvers/iterative.py,sha256=CIxJHjGnCaIjXbtO2NxV60yeDpcCbSD6Bp0xR-7vOf0,12944
|
21
|
-
pymoto/solvers/matrix_checks.py,sha256=bbrfjpTSWWnuQW3xY0_CYE8yrh5gA9K5b1LzHEOFAxI,1663
|
22
|
-
pymoto/solvers/solvers.py,sha256=RwHjZYYlE3oA0U9k7ukla2gOdmq57rSSJQvHqjaM7JU,10626
|
23
|
-
pymoto/solvers/sparse.py,sha256=w8XBlFBIfOpNnfRdLWhLzzqtD8YVxMnDBuhIabFfQQc,16664
|
24
|
-
pyMOTO-1.5.0.dist-info/LICENSE,sha256=ZXMC2Txpzs-dBwz9Me4_1rQCSVl4P1B27MomNi43F30,1072
|
25
|
-
pyMOTO-1.5.0.dist-info/METADATA,sha256=hC38SdgeKEK5NkNDh-gwc4Gz2JOFSymJB-eAMXl7HX4,5006
|
26
|
-
pyMOTO-1.5.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
27
|
-
pyMOTO-1.5.0.dist-info/top_level.txt,sha256=EdvAUSmFMaiqhuEZW8jxANMiK-LdPtlmDWL6SfmCdUU,7
|
28
|
-
pyMOTO-1.5.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
29
|
-
pyMOTO-1.5.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|