femagtools 1.8.5__py3-none-any.whl → 1.8.7__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 +1 -1
- femagtools/bch.py +16 -9
- femagtools/dxfsl/area.py +3 -0
- femagtools/dxfsl/conv.py +1 -8
- femagtools/dxfsl/converter.py +62 -144
- femagtools/dxfsl/geom.py +49 -0
- femagtools/femag.py +13 -72
- femagtools/fsl.py +6 -3
- femagtools/isa7.py +47 -3
- femagtools/losscoeffs.py +29 -3
- femagtools/machine/afpm.py +82 -21
- femagtools/mcv.py +162 -7
- femagtools/multiproc.py +2 -1
- femagtools/parstudy.py +3 -1
- femagtools/plot/__init__.py +1 -0
- femagtools/plot/bch.py +172 -36
- femagtools/plot/machine.py +100 -0
- femagtools/plot/nc.py +13 -0
- femagtools/poc.py +10 -0
- femagtools/shortcircuit.py +378 -0
- femagtools/templates/psi-torq-rem-rot.mako +127 -0
- femagtools/utils.py +2 -0
- femagtools/zmq.py +22 -4
- {femagtools-1.8.5.dist-info → femagtools-1.8.7.dist-info}/METADATA +1 -1
- {femagtools-1.8.5.dist-info → femagtools-1.8.7.dist-info}/RECORD +30 -27
- tests/test_nc.py +11 -0
- {femagtools-1.8.5.dist-info → femagtools-1.8.7.dist-info}/LICENSE +0 -0
- {femagtools-1.8.5.dist-info → femagtools-1.8.7.dist-info}/WHEEL +0 -0
- {femagtools-1.8.5.dist-info → femagtools-1.8.7.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.5.dist-info → femagtools-1.8.7.dist-info}/top_level.txt +0 -0
    
        femagtools/plot/bch.py
    CHANGED
    
    | @@ -22,6 +22,26 @@ except ImportError:   # ModuleNotFoundError: | |
| 22 22 | 
             
            logger = logging.getLogger("femagtools.plot.bch")
         | 
| 23 23 |  | 
| 24 24 |  | 
| 25 | 
            +
            def find_peaks_and_valleys(t, y):
         | 
| 26 | 
            +
                """ return peaks and valleys of y with maximum amplitude
         | 
| 27 | 
            +
                """
         | 
| 28 | 
            +
                peaks = (np.diff(np.sign(np.diff(y))) < 0).nonzero()[0] + 1
         | 
| 29 | 
            +
                if len(peaks > 0):
         | 
| 30 | 
            +
                    ip = np.argmax(y[peaks])
         | 
| 31 | 
            +
                    pv = {'yp': y[peaks][ip], 'tp': t[peaks][ip]}
         | 
| 32 | 
            +
                else:
         | 
| 33 | 
            +
                    pv = {'yp': [], 'tp': []}
         | 
| 34 | 
            +
                valleys = (np.diff(np.sign(np.diff(y))) > 0).nonzero()[0] + 1
         | 
| 35 | 
            +
                if len(valleys > 0):
         | 
| 36 | 
            +
                    iv = np.argmin(y[valleys])
         | 
| 37 | 
            +
                    pv.update({'yv': y[valleys][iv], 'tv': t[valleys][iv]})
         | 
| 38 | 
            +
                else:
         | 
| 39 | 
            +
                    pv.update({'yv': [], 'tv': []})
         | 
| 40 | 
            +
                pv.update({'peaks': y[peaks], 'valleys': y[valleys],
         | 
| 41 | 
            +
                           'tpeaks': t[peaks], 'tvalleys': t[valleys]})
         | 
| 42 | 
            +
                return pv
         | 
| 43 | 
            +
             | 
| 44 | 
            +
             | 
| 25 45 | 
             
            def _create_3d_axis():
         | 
| 26 46 | 
             
                """creates a subplot with 3d projection if one does not already exist"""
         | 
| 27 47 | 
             
                from matplotlib.projections import get_projection_class
         | 
| @@ -495,48 +515,151 @@ def cogging(bch, title=''): | |
| 495 515 | 
             
                    fig.subplots_adjust(top=0.92)
         | 
| 496 516 |  | 
| 497 517 |  | 
| 498 | 
            -
            def  | 
| 499 | 
            -
                """ | 
| 500 | 
            -
                 | 
| 501 | 
            -
             | 
| 502 | 
            -
                 | 
| 503 | 
            -
                 | 
| 504 | 
            -
             | 
| 505 | 
            -
             | 
| 506 | 
            -
                     | 
| 507 | 
            -
             | 
| 508 | 
            -
                 | 
| 509 | 
            -
                 | 
| 510 | 
            -
                 | 
| 518 | 
            +
            def demagnetization(demag, ax=0):
         | 
| 519 | 
            +
                """plot rel. remanence vs. current"""
         | 
| 520 | 
            +
                if ax == 0:
         | 
| 521 | 
            +
                    ax = plt.gca()
         | 
| 522 | 
            +
                scale = 1
         | 
| 523 | 
            +
                unit = 'A'
         | 
| 524 | 
            +
                if np.max(demag['i1']) > 25e3:
         | 
| 525 | 
            +
                    scale = 1e-3
         | 
| 526 | 
            +
                    unit = 'kA'
         | 
| 527 | 
            +
                i1 = [scale*x for x in demag['i1']]
         | 
| 528 | 
            +
                ax.plot(i1, demag['rr'], 'o', color='C0')
         | 
| 529 | 
            +
                ax.plot(i1, demag['rr'], color='C0')
         | 
| 530 | 
            +
                rrmin = 0.6
         | 
| 531 | 
            +
                if demag.get('i1c', 0):
         | 
| 532 | 
            +
                    Icrit = scale*demag['i1c']
         | 
| 533 | 
            +
                    Hk = demag['Hk']
         | 
| 534 | 
            +
                    Tmag = demag['Tmag']
         | 
| 535 | 
            +
                    di = 0.05*np.max(i1)
         | 
| 536 | 
            +
                    rrmin = min(0.6, np.min(demag['rr']))
         | 
| 537 | 
            +
                    ax.plot([Icrit, Icrit], [rrmin, 1], 'k--')
         | 
| 538 | 
            +
                    ax.annotate(
         | 
| 539 | 
            +
                        f'Icrit = {Icrit:.1f}{unit}\nHk = {Hk:.1f} kA/m\nTmag={Tmag:.1f} °C',
         | 
| 540 | 
            +
                        xy=(Icrit, rrmin),
         | 
| 541 | 
            +
                        xytext=(Icrit-di, rrmin+0.1*(1-rrmin)), ha='right',
         | 
| 542 | 
            +
                        bbox={'facecolor': 'white',
         | 
| 543 | 
            +
                              'edgecolor': 'white'})
         | 
| 544 | 
            +
                ax.set_ylim([rrmin, 1.01])
         | 
| 545 | 
            +
                ax.set_ylabel('Rel. Remanence')
         | 
| 546 | 
            +
                ax.set_xlabel(f'Phase Current / {unit}')
         | 
| 547 | 
            +
                ax.grid()
         | 
| 548 | 
            +
             | 
| 549 | 
            +
             | 
| 550 | 
            +
            def transientsc_currents(scData, ax=0, title='', set_xlabel=True):
         | 
| 551 | 
            +
                """plot transient shortcircuit currents vs time"""
         | 
| 552 | 
            +
                if ax == 0:
         | 
| 553 | 
            +
                    ax = plt.gca()
         | 
| 511 554 | 
             
                ax.grid(True)
         | 
| 512 | 
            -
                 | 
| 555 | 
            +
                if title:
         | 
| 556 | 
            +
                    ax.set_title(title)
         | 
| 557 | 
            +
                istat = np.array([scData[i]
         | 
| 513 558 | 
             
                                  for i in ('ia', 'ib', 'ic')])
         | 
| 559 | 
            +
                pv = [find_peaks_and_valleys(
         | 
| 560 | 
            +
                    np.array(scData['time']), i1)
         | 
| 561 | 
            +
                      for i1 in istat]
         | 
| 562 | 
            +
                try:
         | 
| 563 | 
            +
                    ipvmax = np.argmax(
         | 
| 564 | 
            +
                        [y['yp'] if np.abs(y['yp']) > np.abs(y['yv']) else y['yv']
         | 
| 565 | 
            +
                         for y in pv if y['yp']])
         | 
| 566 | 
            +
                    imax = pv[ipvmax]['yp'] if np.abs(pv[ipvmax]['yp']) > np.abs(pv[ipvmax]['yv']) else pv[ipvmax]['yv']
         | 
| 567 | 
            +
                    iac = [pv[ipvmax]['tpeaks'][-1], pv[ipvmax]['peaks'][-1]]
         | 
| 568 | 
            +
                except KeyError:
         | 
| 569 | 
            +
                    pass
         | 
| 514 570 | 
             
                if np.max(istat) > 4000:
         | 
| 515 571 | 
             
                    istat *= 1e-3
         | 
| 516 | 
            -
                     | 
| 572 | 
            +
                    try:
         | 
| 573 | 
            +
                        imax *= 1e-3
         | 
| 574 | 
            +
                        iac[1] *= 1e-3
         | 
| 575 | 
            +
                    except NameError:
         | 
| 576 | 
            +
                        pass
         | 
| 577 | 
            +
                    ax.set_ylabel('Currents / kA')
         | 
| 517 578 | 
             
                else:
         | 
| 518 | 
            -
                    ax. | 
| 579 | 
            +
                    ax.set_ylabel('Currents / A')
         | 
| 519 580 |  | 
| 520 581 | 
             
                for i, iph in zip(('ia', 'ib', 'ic'), istat):
         | 
| 521 | 
            -
                    ax.plot( | 
| 522 | 
            -
                 | 
| 582 | 
            +
                    ax.plot(scData['time'], iph, label=i)
         | 
| 583 | 
            +
                try:
         | 
| 584 | 
            +
                    ax.plot([pv[ipvmax]['tp']], [imax], '.')
         | 
| 585 | 
            +
                    ax.plot([iac[0]], [iac[1]], '.')
         | 
| 586 | 
            +
                    dtx = (scData['time'][-1]-scData['time'][0])/75
         | 
| 587 | 
            +
                    dy = imax/25
         | 
| 588 | 
            +
                    ax.annotate(f'Imax = {imax:.1f}',
         | 
| 589 | 
            +
                                xy=(pv[ipvmax]['tp'], imax),
         | 
| 590 | 
            +
                                xytext=(pv[ipvmax]['tp']+dtx, imax-dy))
         | 
| 591 | 
            +
                    dy = iac[1]/25
         | 
| 592 | 
            +
                    ax.annotate(f'I = {iac[1]:.1f}',
         | 
| 593 | 
            +
                                xy=iac,
         | 
| 594 | 
            +
                                xytext=(iac[0]+dtx, iac[1]-dy))
         | 
| 595 | 
            +
                except NameError:
         | 
| 596 | 
            +
                    pass
         | 
| 597 | 
            +
                if set_xlabel:
         | 
| 598 | 
            +
                    ax.set_xlabel('Time / s')
         | 
| 523 599 | 
             
                ax.legend()
         | 
| 524 600 |  | 
| 525 | 
            -
             | 
| 526 | 
            -
             | 
| 527 | 
            -
                 | 
| 528 | 
            -
                 | 
| 529 | 
            -
             | 
| 601 | 
            +
             | 
| 602 | 
            +
            def transientsc_torque(scData, ax=0, title='', set_xlabel=True):
         | 
| 603 | 
            +
                """plot transient shortcircuit torque vs time"""
         | 
| 604 | 
            +
                if ax == 0:
         | 
| 605 | 
            +
                    ax = plt.gca()
         | 
| 606 | 
            +
                if title:
         | 
| 607 | 
            +
                    ax.set_title(title)
         | 
| 608 | 
            +
                pv = find_peaks_and_valleys(
         | 
| 609 | 
            +
                    np.array(scData['time']), np.array(scData['torque']))
         | 
| 610 | 
            +
                try:
         | 
| 611 | 
            +
                    tqmax = pv['yp'] if np.abs(pv['yp']) > np.abs(pv['yv']) else pv['yv']
         | 
| 612 | 
            +
                    tp = pv['tp'] if np.abs(pv['yp']) > np.abs(pv['yv']) else pv['tv']
         | 
| 613 | 
            +
                    tc = [pv['tpeaks'][-1], pv['peaks'][-1]]
         | 
| 614 | 
            +
                except (KeyError, ValueError):
         | 
| 615 | 
            +
                    pass
         | 
| 616 | 
            +
                torque = np.array(scData['torque'])
         | 
| 530 617 | 
             
                if np.max(torque) > 4000:
         | 
| 531 618 | 
             
                    torque *= 1e-3
         | 
| 532 | 
            -
                     | 
| 619 | 
            +
                    try:
         | 
| 620 | 
            +
                        tqmax *= 1e-3
         | 
| 621 | 
            +
                        tc[1] *= 1e-3
         | 
| 622 | 
            +
                    except NameError:
         | 
| 623 | 
            +
                        pass
         | 
| 624 | 
            +
                    ax.set_ylabel('Torque / kNm')
         | 
| 533 625 | 
             
                else:
         | 
| 534 | 
            -
                    ax. | 
| 626 | 
            +
                    ax.set_ylabel('Torque / Nm')
         | 
| 535 627 |  | 
| 536 628 | 
             
                ax.grid(True)
         | 
| 537 | 
            -
                ax.plot( | 
| 538 | 
            -
                 | 
| 629 | 
            +
                ax.plot(scData['time'], torque)
         | 
| 630 | 
            +
                try:
         | 
| 631 | 
            +
                    ax.plot([tp], [tqmax], '.')
         | 
| 632 | 
            +
                    ax.plot([tc[0]], [tc[1]], '.')
         | 
| 633 | 
            +
                    dtx = (scData['time'][-1]-scData['time'][0])/75
         | 
| 634 | 
            +
                    dy = tqmax/25
         | 
| 635 | 
            +
                    ax.annotate(f'Tmax = {tqmax:.1f}',
         | 
| 636 | 
            +
                                xy=(tp, tqmax),
         | 
| 637 | 
            +
                                xytext=(tp+dtx, tqmax-dy))
         | 
| 638 | 
            +
                    dy = tc[1]/25
         | 
| 639 | 
            +
                    ax.annotate(f'T = {tc[1]:.1f}',
         | 
| 640 | 
            +
                                xy=tc,
         | 
| 641 | 
            +
                                xytext=(tc[0]+dtx, tc[1]))
         | 
| 642 | 
            +
                except NameError:
         | 
| 643 | 
            +
                    pass
         | 
| 644 | 
            +
                if set_xlabel:
         | 
| 645 | 
            +
                    ax.set_xlabel('Time / s')
         | 
| 646 | 
            +
             | 
| 647 | 
            +
            def transientsc(bch, title=''):
         | 
| 648 | 
            +
                """creates a transient short circuit plot"""
         | 
| 649 | 
            +
                try:
         | 
| 650 | 
            +
                    scData = bch.scData
         | 
| 651 | 
            +
                except AttributeError:
         | 
| 652 | 
            +
                    scData = bch
         | 
| 653 | 
            +
                cols = 1
         | 
| 654 | 
            +
                rows = 2
         | 
| 655 | 
            +
                htitle = 1.5 if title else 0
         | 
| 656 | 
            +
                fig, axs = plt.subplots(nrows=rows, ncols=cols, sharex=True,
         | 
| 657 | 
            +
                                        figsize=(10, 3*rows + htitle))
         | 
| 658 | 
            +
                if title:
         | 
| 659 | 
            +
                    fig.suptitle(title, fontsize=16)
         | 
| 539 660 |  | 
| 661 | 
            +
                transientsc_currents(scData, axs[0], set_xlabel=False)
         | 
| 662 | 
            +
                transientsc_torque(scData, axs[1])
         | 
| 540 663 | 
             
                fig.tight_layout(h_pad=2)
         | 
| 541 664 | 
             
                if title:
         | 
| 542 665 | 
             
                    fig.subplots_adjust(top=0.92)
         | 
| @@ -550,22 +673,35 @@ def transientsc_demag(demag, magnet=0, title='', ax=0): | |
| 550 673 | 
             
                """
         | 
| 551 674 | 
             
                if ax == 0:
         | 
| 552 675 | 
             
                    ax = plt.gca()
         | 
| 553 | 
            -
                 | 
| 554 | 
            -
             | 
| 555 | 
            -
             | 
| 556 | 
            -
             | 
| 557 | 
            -
             | 
| 676 | 
            +
                if type(d) == list:
         | 
| 677 | 
            +
                    pos = [d['displ'] for d in demag if 'displ' in d]
         | 
| 678 | 
            +
                    hmax = [-d['H_max'] for d in demag if 'H_max' in d]
         | 
| 679 | 
            +
                    havg = [-d['H_av'] for d in demag if 'H_av' in d]
         | 
| 680 | 
            +
                    hclim = [-d['lim_hc'] for d in demag if 'lim_hc' in d][0]
         | 
| 681 | 
            +
                else:
         | 
| 682 | 
            +
                    pos = demag['displ']
         | 
| 683 | 
            +
                    hmax = demag['H_max']
         | 
| 684 | 
            +
                    havg = demag['H_av']
         | 
| 685 | 
            +
                    hclim = demag['Hk']
         | 
| 558 686 | 
             
                ax.set_title('Transient Short Circuit Demagnetization [kA/m]')
         | 
| 559 687 | 
             
                ax.plot(pos, hmax,
         | 
| 560 688 | 
             
                        label='H Max {:4.2f} kA/m'.format(max(hmax)))
         | 
| 561 689 | 
             
                ax.plot(pos, havg,
         | 
| 562 690 | 
             
                        label='H Avg {:4.2f} kA/m'.format(max(havg)))
         | 
| 563 | 
            -
                 | 
| 564 | 
            -
             | 
| 691 | 
            +
                if len(hclim) > 1:
         | 
| 692 | 
            +
                    ax.plot([pos[0], pos[-1]], [hclim,hclim], color='C3',
         | 
| 693 | 
            +
                            linestyle='dashed',
         | 
| 694 | 
            +
                            label='Hc {:4.2f} kA/m'.format(hclim))
         | 
| 695 | 
            +
                if 'Tmag' in demag:
         | 
| 696 | 
            +
                    Tmag = demag['Tmag']
         | 
| 697 | 
            +
                elif magnet:
         | 
| 698 | 
            +
                    Tmag = magnet['Tmag']
         | 
| 699 | 
            +
                else:
         | 
| 700 | 
            +
                    Tmag = ''
         | 
| 565 701 | 
             
                ax.set_xlabel('Rotor Position / °')
         | 
| 566 702 | 
             
                ax.grid(True)
         | 
| 567 | 
            -
                if  | 
| 568 | 
            -
                    ax.legend(title=f"Magnet Temperature { | 
| 703 | 
            +
                if Tmag:
         | 
| 704 | 
            +
                    ax.legend(title=f"Magnet Temperature {Tmag}°C")
         | 
| 569 705 | 
             
                else:
         | 
| 570 706 | 
             
                    ax.legend()
         | 
| 571 707 |  | 
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            """
         | 
| 2 | 
            +
            Create longitudinal drawing of radial flux machine
         | 
| 3 | 
            +
            """
         | 
| 4 | 
            +
            import matplotlib.pyplot as plt
         | 
| 5 | 
            +
            import matplotlib.patches as pch
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            def _draw_shaft(ax, dy2, lfe):
         | 
| 8 | 
            +
                xx = (0.0, lfe, lfe, 0.0)
         | 
| 9 | 
            +
                yy = (dy2/2, dy2/2, -dy2/2, -dy2/2)
         | 
| 10 | 
            +
                ax.fill(xx, yy,
         | 
| 11 | 
            +
                        facecolor='lightgrey',
         | 
| 12 | 
            +
                        edgecolor='black',
         | 
| 13 | 
            +
                        linewidth=0)
         | 
| 14 | 
            +
                xx = (-lfe/4, lfe+lfe/4, lfe+lfe/4, -lfe/4)
         | 
| 15 | 
            +
                yy = (dy2/4, dy2/4, -dy2/4, -dy2/4)
         | 
| 16 | 
            +
                ax.fill(xx, yy,
         | 
| 17 | 
            +
                        facecolor='lightgrey',
         | 
| 18 | 
            +
                        edgecolor='black',
         | 
| 19 | 
            +
                        linewidth=0)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            def _draw_rotor(ax, da1, dy2, lfe):
         | 
| 22 | 
            +
                ag = 0.02*da1
         | 
| 23 | 
            +
                xx = (0.0, lfe, lfe, 0.0)
         | 
| 24 | 
            +
                yy = (dy2/2, dy2/2, da1/2-ag, da1/2-ag)
         | 
| 25 | 
            +
                ax.fill(xx, yy,
         | 
| 26 | 
            +
                        facecolor='skyblue',
         | 
| 27 | 
            +
                        edgecolor='black',
         | 
| 28 | 
            +
                        linewidth=0)
         | 
| 29 | 
            +
                yy = (-dy2/2, -dy2/2, -da1/2+ag, -da1/2+ag)
         | 
| 30 | 
            +
                ax.fill(xx, yy,
         | 
| 31 | 
            +
                        facecolor='skyblue',
         | 
| 32 | 
            +
                        edgecolor='black',
         | 
| 33 | 
            +
                        linewidth=0)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            def _draw_stator(ax, da1, dy1, lfe):
         | 
| 36 | 
            +
                xx = (0.0, lfe, lfe, 0.0)
         | 
| 37 | 
            +
                yy = (da1/2, da1/2, dy1/2, dy1/2)
         | 
| 38 | 
            +
                # yoke
         | 
| 39 | 
            +
                ax.fill(xx, yy,
         | 
| 40 | 
            +
                        facecolor='skyblue',
         | 
| 41 | 
            +
                        edgecolor='black',
         | 
| 42 | 
            +
                        linewidth=0)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                yy = (-da1/2, -da1/2, -dy1/2, -dy1/2)
         | 
| 45 | 
            +
                ax.fill(xx, yy,
         | 
| 46 | 
            +
                        facecolor='skyblue',
         | 
| 47 | 
            +
                        edgecolor='black',
         | 
| 48 | 
            +
                        linewidth=0)
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                # winding
         | 
| 51 | 
            +
                yh = (dy1-da1)/2
         | 
| 52 | 
            +
                xx = (-yh/2, 0, 0, -yh/2)
         | 
| 53 | 
            +
                yy = (da1/2, da1/2, dy1/2-yh/2, dy1/2-yh/2)
         | 
| 54 | 
            +
                ax.fill(xx, yy, facecolor='gold',
         | 
| 55 | 
            +
                            edgecolor='black',
         | 
| 56 | 
            +
                            linewidth=0)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                xx = (lfe, lfe+yh/2, lfe+yh/2, lfe)
         | 
| 59 | 
            +
                ax.fill(xx, yy, facecolor='gold',
         | 
| 60 | 
            +
                            edgecolor='black',
         | 
| 61 | 
            +
                            linewidth=0)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                yy = (-da1/2, -da1/2, -dy1/2+yh/2, -dy1/2+yh/2)
         | 
| 64 | 
            +
                ax.fill(xx, yy, facecolor='gold',
         | 
| 65 | 
            +
                            edgecolor='black',
         | 
| 66 | 
            +
                            linewidth=0)
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                xx = (-yh/2, 0, 0, -yh/2)
         | 
| 69 | 
            +
                ax.fill(xx, yy, facecolor='gold',
         | 
| 70 | 
            +
                            edgecolor='black',
         | 
| 71 | 
            +
                            linewidth=0)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            def machine(machine, ax):
         | 
| 74 | 
            +
                dy2 = machine['inner_diam']*1e3
         | 
| 75 | 
            +
                dy1 = machine['outer_diam']*1e3
         | 
| 76 | 
            +
                da1 = machine['bore_diam']*1e3
         | 
| 77 | 
            +
                lfe = machine['lfe']*1e3
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                _draw_rotor(ax, da1, dy2, lfe)
         | 
| 80 | 
            +
                _draw_stator(ax, da1, dy1, lfe)
         | 
| 81 | 
            +
                _draw_shaft(ax, dy2, lfe)
         | 
| 82 | 
            +
                ax.set_aspect('equal')
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                for loc, spine in ax.spines.items():
         | 
| 85 | 
            +
                    spine.set_color('none')  # don't draw spine
         | 
| 86 | 
            +
                #ax.yaxis.set_ticks([])
         | 
| 87 | 
            +
                #ax.xaxis.set_ticks([])
         | 
| 88 | 
            +
             | 
| 89 | 
            +
             | 
| 90 | 
            +
            if __name__ == '__main__':
         | 
| 91 | 
            +
                machine1 = {
         | 
| 92 | 
            +
                    "outer_diam": 0.2442,
         | 
| 93 | 
            +
                    "bore_diam": 0.179,
         | 
| 94 | 
            +
                    "inner_diam": 0.06,
         | 
| 95 | 
            +
                    "airgap": 0.7e-3,
         | 
| 96 | 
            +
                    "lfe": 0.083,
         | 
| 97 | 
            +
                }
         | 
| 98 | 
            +
                fig, ax = plt.subplots()
         | 
| 99 | 
            +
                machine(machine1, ax)
         | 
| 100 | 
            +
                plt.show()
         | 
    
        femagtools/plot/nc.py
    CHANGED
    
    | @@ -130,6 +130,19 @@ def demag(isa, cmap=DEFAULT_CMAP, ax=0): | |
| 130 130 | 
             
                logger.info("Max demagnetization %f", np.max(demag))
         | 
| 131 131 |  | 
| 132 132 |  | 
| 133 | 
            +
            def remanence(isa, cmap=DEFAULT_CMAP, ax=0):
         | 
| 134 | 
            +
                """plot remanence of NC/I7/ISA7 model
         | 
| 135 | 
            +
                Args:
         | 
| 136 | 
            +
                  isa: Isa7/NC object
         | 
| 137 | 
            +
                """
         | 
| 138 | 
            +
                emag = [e for e in isa.elements if e.is_magnet()]
         | 
| 139 | 
            +
                rem = np.linalg.norm([e.remanence(isa.MAGN_TEMPERATURE)
         | 
| 140 | 
            +
                                      for e in emag], axis=1)
         | 
| 141 | 
            +
                _contour(ax, f'Remanence at {isa.MAGN_TEMPERATURE} °C (min {np.min(rem):.1f} T)',
         | 
| 142 | 
            +
                         emag, rem, 'T', cmap, isa)
         | 
| 143 | 
            +
                logger.info("Min remanence %f", np.min(rem))
         | 
| 144 | 
            +
             | 
| 145 | 
            +
             | 
| 133 146 | 
             
            def demag_pos(isa, pos=-1, icur=-1, ibeta=-1, cmap=DEFAULT_CMAP, ax=0):
         | 
| 134 147 | 
             
                """plot demag of NC/I7/ISA7 model at rotor position
         | 
| 135 148 | 
             
                Args:
         | 
    
        femagtools/poc.py
    CHANGED
    
    | @@ -75,6 +75,7 @@ class Poc: | |
| 75 75 | 
             
                    if self.pole_pitch:
         | 
| 76 76 | 
             
                        content.append("{0}".format(self.pole_pitch))
         | 
| 77 77 | 
             
                    if self.pocType in ['fun', 'har', 'hsp']:
         | 
| 78 | 
            +
                        self.data_check()
         | 
| 78 79 | 
             
                        func_steps = len(self.func_current)
         | 
| 79 80 | 
             
                        content += [f"{self.pocType}", f"{func_steps}"]
         | 
| 80 81 | 
             
                        if (self.pocType == 'fun' and
         | 
| @@ -122,6 +123,7 @@ class Poc: | |
| 122 123 | 
             
                        import re
         | 
| 123 124 | 
             
                        for i in range(func_steps-1):
         | 
| 124 125 | 
             
                            l = re.split(';|\t|,| ', pocfile.readline().strip())
         | 
| 126 | 
            +
                            l = [i for i in l if i]  # remove empty items
         | 
| 125 127 | 
             
                            if len(l) > 2:
         | 
| 126 128 | 
             
                                self.harmonic_id.append(int(l[0]))
         | 
| 127 129 | 
             
                                self.func_current.append(float(l[1]))
         | 
| @@ -129,6 +131,7 @@ class Poc: | |
| 129 131 | 
             
                            else:
         | 
| 130 132 | 
             
                                self.func_current.append(float(l[0]))
         | 
| 131 133 | 
             
                                self.func_phi.append(float(l[1]))
         | 
| 134 | 
            +
                        self.data_check()
         | 
| 132 135 | 
             
                    else:
         | 
| 133 136 | 
             
                        self.shape_current=self.pocType
         | 
| 134 137 | 
             
                        self.pocType='Function'
         | 
| @@ -139,6 +142,13 @@ class Poc: | |
| 139 142 | 
             
                    except ValueError:
         | 
| 140 143 | 
             
                        pass
         | 
| 141 144 |  | 
| 145 | 
            +
                def data_check( self ):
         | 
| 146 | 
            +
                    """simple phi data increasing check"""
         | 
| 147 | 
            +
                    import numpy as np
         | 
| 148 | 
            +
                    if (not np.all(np.diff(self.func_phi) > 0)
         | 
| 149 | 
            +
                        and np.all(np.diff(self.func_current) > 0)):
         | 
| 150 | 
            +
                        self.func_phi, self.func_current = self.func_current, self.func_phi
         | 
| 151 | 
            +
             | 
| 142 152 | 
             
                def getProps( self ):
         | 
| 143 153 | 
             
                    keys=['key_winding',
         | 
| 144 154 | 
             
                          'phi_voltage_winding',
         |