Browse Source

Squashed commit of the following:

commit 4939bc8993
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Oct 25 22:04:16 2020 +0100

    added cppduals cleanly

commit 834cbc5aba
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Oct 25 22:03:40 2020 +0100

    remove cppduals

commit 69b922cef2
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Oct 25 21:59:00 2020 +0100

    cppduals in new diretory

commit 4337cc0e33
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Oct 25 21:49:52 2020 +0100

    hicum license cleaning

commit ba439dfdf5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Oct 17 13:19:05 2020 +0200

    moved sh stamp, working

commit 29028ff34d
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Oct 17 12:56:54 2020 +0200

    forgot something

commit 5743d2b551
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Oct 17 12:54:35 2020 +0200

    rth stamp moved (no yet working)

commit 42d61da3eb
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Oct 17 11:54:10 2020 +0200

    Hicum C/C++ code now under 3-clause BSD

commit 5088e869ea
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Oct 17 11:44:57 2020 +0200

    cleaned comments

commit 18fc66e71b
Author: dwarning <dwarning>
Date:   Sat Sep 12 19:48:11 2020 +0200

    rm some less useful comments - no code change

commit 861f286fda
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Sep 8 15:45:46 2020 +0200

    clean hicum2ask

commit a52274ba7d
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Sep 8 15:43:18 2020 +0200

    fix nqs transient

commit fa7f96b4af
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Sep 7 13:17:42 2020 +0200

    fix HICUM csu readin

commit 23183f10b6
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Aug 8 15:35:32 2020 +0200

    added it to Hicum states -> noise

commit 020fc70607
Author: dwarning <dwarning>
Date:   Tue Aug 4 09:18:05 2020 +0200

    change inst to here

commit 33d06d9732
Author: dwarning <dwarning>
Date:   Tue Aug 4 09:12:37 2020 +0200

    reintroduce iavl and correct ibici shot noise

commit 7251265231
Author: dwarning <dwarning>
Date:   Tue Aug 4 08:59:26 2020 +0200

    more reasonable plot scaling

commit 67919b9bd8
Author: dwarning <dwarning>
Date:   Tue Aug 4 08:56:04 2020 +0200

    yet another try for flicker noise scaling

commit 689177a55f
Author: dwarning <dwarning>
Date:   Mon Aug 3 10:41:44 2020 +0200

    correct multiplier scaling for rsu

commit 58b89af40a
Author: dwarning <dwarning>
Date:   Sun Aug 2 18:57:14 2020 +0200

    prevent division by 0 for rbi

commit a4e7eb5b6c
Author: dwarning <dwarning>
Date:   Sun Aug 2 18:25:51 2020 +0200

    fix instance multiplier application for noise

commit 36862a7bc6
Author: dwarning <dwarning>
Date:   Fri Jul 31 21:06:13 2020 +0200

    white spaces

commit 8a0504bb13
Author: dwarning <dwarning>
Date:   Fri Jul 31 18:32:45 2020 +0200

    add a transient analysis example

commit c1f0348697
Author: dwarning <dwarning>
Date:   Fri Jul 31 18:31:10 2020 +0200

    still problems in different terminal configurations

commit 26e026e4c8
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jul 31 14:36:34 2020 +0200

    fix stamp for Cth

commit dd84b1fcd3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jul 31 14:22:16 2020 +0200

    fix bug in Cscp stamp

commit 1f13d2526f
Author: dwarning <dwarning>
Date:   Fri Jul 31 11:29:25 2020 +0200

    visualc mod - no impact to hicum

commit cff491feca
Author: dwarning <dwarning>
Date:   Fri Jul 31 10:59:52 2020 +0200

    wrong and twice assignment

commit 4a9dc52037
Author: dwarning <dwarning>
Date:   Fri Jul 31 10:00:20 2020 +0200

    twice assignment

commit c76bcc7cca
Author: dwarning <dwarning>
Date:   Thu Jul 30 12:36:30 2020 +0200

    delete base nodes from inner to outer

commit 4a472a3451
Author: dwarning <dwarning>
Date:   Mon Jul 27 15:34:15 2020 +0200

    correct the switch for Vbici limiting

commit f47bc449b3
Author: dwarning <dwarning>
Date:   Sun Jul 26 21:56:48 2020 +0200

    few parameter adaptions to version 2.40

commit 5901ec2902
Author: dwarning <dwarning>
Date:   Sun Jul 26 16:37:44 2020 +0200

    sign for CONSTCtoK must be +

commit 556171a905
Author: dwarning <dwarning>
Date:   Sun Jul 26 16:36:15 2020 +0200

    rbi is 0 if nodes are collapsed

commit 724887f32c
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 26 12:45:15 2020 +0200

    add ngspice Temperature clipping in HICUM

commit d735f445e5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 26 12:13:39 2020 +0200

    removed rbi fallback, removed rth_de

commit 162b174acd
Author: dwarning <dwarning>
Date:   Sat Jul 25 12:31:05 2020 +0200

    add few small-signal parameter

commit 5afb2dc8c8
Author: dwarning <dwarning>
Date:   Fri Jul 24 16:49:11 2020 +0200

    reduce unnecassary inits

commit 0efc047f5f
Author: dwarning <dwarning>
Date:   Fri Jul 24 16:03:10 2020 +0200

    few typos and comments

commit 14a5cd873b
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jul 24 11:25:51 2020 +0200

    remove rbi stamps if nodes collapsed finish

commit f5461183f3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jul 24 11:17:33 2020 +0200

    hicumL2 load -> remove stamp for rbi, if node BP BI collapsed

commit 00f51465e3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jul 24 11:07:58 2020 +0200

    finish cleaning

commit 019ef4e07e
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jul 24 10:50:05 2020 +0200

    moving derivatives from _Tdev to _Vrth in a clean way (start)

commit 154036c09f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jul 23 16:50:31 2020 +0200

    consistent derivative with Vrth/Tdev=> will rework this, I do not like
    this

commit 03c3efd762
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jul 23 16:22:46 2020 +0200

    finally: avalanche at very high T fix

commit 64704fd53e
Merge: a26b3ee2b f6db74ac5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jul 23 15:56:29 2020 +0200

    Merge remote-tracking branch 'origin/markus_dev' into markus_dev

commit a26b3ee2b20c668df6d41938a06472440803855f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jul 23 15:56:17 2020 +0200

    start bugfix

commit f6db74ac50da167d3081c1c7e8a2e5eda254183f
Author: dwarning <dwarning>
Date:   Tue Jul 21 18:56:32 2020 +0200

    rm obsolete files

commit 9854038f2c22acf688fa494496ca7b71855198ea
Author: dwarning <dwarning>
Date:   Tue Jul 21 16:48:56 2020 +0200

    allow periphal resistors and rbi default 0

commit 34f579c08f9b8378c29074678e9cb651f49092ce
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jul 21 13:05:54 2020 +0200

    fix bug node collapsing BI BP

commit 6f5627f44169bd4eb72dea3fb7d8f6d600ddcdb5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jul 21 11:48:22 2020 +0200

    node collapsing BI BP HICUM

commit 187d391383cfe76fb5214971ac0ad7fe94b7e397
Author: dwarning <dwarning>
Date:   Tue Jul 21 09:58:59 2020 +0200

    few corrections and reordering

commit 0fc39a424e52804c40003b55ee398812cbaf151b
Author: dwarning <dwarning>
Date:   Mon Jul 20 19:36:15 2020 +0200

    unify nqs flag for setup/unsetup

commit 8944ad2e32e69b87c79d512e05505d41f22bd311
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 18 14:23:30 2020 +0200

    iavl_Vbiei changed sign back ...

commit cc9682f9e541fd16e89cfe687367257be975766f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 18 14:05:12 2020 +0200

    HICUM limit for avalanche

commit 284583e0cc19ff5247d7ce8df8d3292ff60d2062
Author: dwarning <dwarning>
Date:   Wed Jul 15 10:11:46 2020 +0200

    cleanup initial conditions to the traditional spice usage

commit c3cadb8de18cfe522e33c1499e927890a3dbb90d
Author: dwarning <dwarning>
Date:   Wed Jul 15 08:57:03 2020 +0200

    rm unused files

commit 8bc687ddbe66af29234b4aba9279d01fc4d9cda2
Author: dwarning <dwarning>
Date:   Mon Jul 13 10:44:56 2020 +0200

    correct check6 init

commit 9250464ac16eded2cc38deec0bf64af9bc03c639
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 12 14:00:46 2020 +0200

    fix bug in HICUM Qjci calculation, derivatives now more rigorous with
    dual numbers

commit 0fb86510aab4881e858728c588d72852e69df4ca
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 11 15:02:04 2020 +0200

    fix gmin in HICUM

commit 735339e288ceb61d0aa19e09fb6160bd16cbfed6
Merge: fd5b7a648 1659190b2
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 11 14:45:08 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit fd5b7a6485
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 11 14:44:01 2020 +0200

    fix HICUM gmin

commit 1659190b21
Author: dwarning <dwarning>
Date:   Sat Jul 11 09:57:29 2020 +0200

    real node collapsing with slightly better results in qa test

    convergence problems in high current avalanche breakdown still exist

commit aaa94e5c10
Author: dwarning <dwarning>
Date:   Thu Jul 9 18:10:04 2020 +0200

    add hspice to qa

commit 6fe586cf9d
Author: dwarning <dwarning>
Date:   Thu Jul 9 17:26:28 2020 +0200

    relax convergence criteria for qa test

commit 127c2ca451
Author: dwarning <dwarning>
Date:   Thu Jul 9 14:02:48 2020 +0200

    correct loop stopping criteria

commit cfae080c1a
Author: dwarning <dwarning>
Date:   Wed Jul 8 18:02:13 2020 +0200

    examples now version 2.4.0

commit 7b099242da
Author: dwarning <dwarning>
Date:   Wed Jul 8 17:18:28 2020 +0200

    rm non qa file

commit 0c2ef2f7c4
Author: dwarning <dwarning>
Date:   Wed Jul 8 17:15:58 2020 +0200

    qa test is now version 2.4.0

commit e90939126d
Author: dwarning <dwarning>
Date:   Wed Jul 8 17:13:29 2020 +0200

    qa test is now version 2.4.0

commit 114aeee5c5
Author: dwarning <dwarning>
Date:   Wed Jul 8 17:12:05 2020 +0200

    now version 2.4.0

commit 0f33776513
Author: dwarning <dwarning>
Date:   Wed Jul 8 11:40:43 2020 +0200

    reactivate convergence check

commit 6f382c76d8
Author: dwarning <dwarning>
Date:   Wed Jul 8 11:02:30 2020 +0200

    rm old comments and artefacts

commit 5950a2fb03
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jul 8 09:51:03 2020 +0200

    example print for dual number

commit abab054352
Author: dwarning <dwarning>
Date:   Tue Jul 7 08:51:51 2020 +0200

    nqs must set after defaulting model parameters

commit 4c34e54c7b
Author: dwarning <dwarning>
Date:   Mon Jul 6 21:37:04 2020 +0200

    prevent false branch because of rounding error for flcomp

commit 4bb09b35c3
Author: dwarning <dwarning>
Date:   Sun Jul 5 22:16:28 2020 +0200

    clear separation between geometry and temperature scaling

commit 90ab76d876
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 5 18:14:08 2020 +0200

    fix comments in HICUM scaling

commit d7dd26880c
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 5 18:03:23 2020 +0200

    forgot some parameters that depend on "area" and T, but are needed as
    model variables in load

commit 320a66c0a4
Merge: d78032109 b09edc706
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 5 17:27:20 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit d78032109f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jul 5 17:26:45 2020 +0200

    HICUM scaling with "area" and "m" parameters.

commit b09edc706a
Author: dwarning <dwarning>
Date:   Sun Jul 5 17:10:51 2020 +0200

    must fallthrough because icVbe is after icVce

commit dbd99a33a5
Author: dwarning <dwarning>
Date:   Sun Jul 5 09:59:09 2020 +0200

    some useful examples to show hicum2 capabilities

commit ba1c2de06e
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 4 20:21:38 2020 +0200

    added comment to IC vars

commit 6fce26437e
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 4 20:03:13 2020 +0200

    remove hicum inital conditions that are not spice-like

commit aa283f40ef
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jul 4 19:55:58 2020 +0200

    added HICUM pole zero analysis

commit 2165afdf27
Author: dwarning <dwarning>
Date:   Fri Jul 3 17:39:03 2020 +0200

    another cut&paste error and typo

commit 8b680b0c28
Author: dwarning <dwarning>
Date:   Fri Jul 3 17:28:40 2020 +0200

    another cut&paste error

commit f1698c7a81
Author: dwarning <dwarning>
Date:   Fri Jul 3 15:42:37 2020 +0200

    add shot noise sources for it and ibiei

commit 966891d5f7
Author: dwarning <dwarning>
Date:   Fri Jul 3 14:39:31 2020 +0200

    correct multiplier for flicker noise and base-emitter source connection

commit 80e932424f
Author: dwarning <dwarning>
Date:   Fri Jul 3 14:27:52 2020 +0200

    cut&paste error

commit 61ee68c782
Author: dwarning <dwarning>
Date:   Thu Jul 2 21:05:58 2020 +0200

    few corrections in noise model

commit ad16be59ba
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jul 1 14:44:13 2020 +0200

    reorder code

commit e81b41c653
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jul 1 14:33:12 2020 +0200

    fix bugs HICHUM acload

commit 1d5f88e93d
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 28 11:51:10 2020 +0200

    fix bugs

commit bbb729ae8f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 28 11:03:48 2020 +0200

    intermediate state

commit a95aade55a
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 27 20:16:37 2020 +0200

    fix derivative in NQS network

commit a54c52221c
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 27 20:05:58 2020 +0200

    small fixes HICUM

commit 7407302d50
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 27 17:48:23 2020 +0200

    fix bug in HICUMacload

commit bb03c8f663
Merge: 1fa789874 e7d143e04
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 24 13:17:15 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit 1fa7898747
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 24 13:16:20 2020 +0200

    remove nqs from limit function and gmin

commit e7d143e044
Author: dwarning <dwarning>
Date:   Tue Jun 23 18:22:40 2020 +0200

    tk is not an alias parameter name

commit 75e3a4da64
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 23 16:24:59 2020 +0200

    protect nqs network

commit 1c36e997ba
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 23 15:44:46 2020 +0200

    nqs in ac

commit 524abe95f3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 23 15:21:27 2020 +0200

    NQS in acload

commit 0833f955ef
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 23 14:47:35 2020 +0200

    move cross-coupled charges from state vector to here struct

commit 03b4a87477
Author: dwarning <dwarning>
Date:   Mon Jun 22 11:52:42 2020 +0200

    prevent crash if tnode is given but she parameter not

commit 9ab20e2f35
Author: dwarning <dwarning>
Date:   Mon Jun 22 11:51:47 2020 +0200

    alias for tnom

commit 3140bedc3f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 21 21:50:39 2020 +0200

    fix nqs

commit 8dfd2e5a4d
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 20 18:41:35 2020 +0200

    fix HICUM setup

commit f6e4bba9e3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 20 18:40:04 2020 +0200

    finish NQS for DC case

commit 21862cbdb9
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 20 17:55:01 2020 +0200

    first test ok ... modify state vector now

commit 1c5773292e
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 20 17:45:57 2020 +0200

    first implementation of NQS, not tested

commit 4fd24db766
Author: dwarning <dwarning>
Date:   Fri Jun 19 22:12:49 2020 +0200

    external temp node has number 5

commit 8fb3f2ce9a
Merge: b7e4c39d8 5f4085d4a
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jun 19 19:05:31 2020 +0200

    Merge remote-tracking branch 'origin/markus_dev' into markus_dev

commit b7e4c39d80b4b93ae58efc7449d43f39712f7bb9
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jun 19 19:03:46 2020 +0200

    fix unset t node HICUM

commit 5f4085d4a8193cc9978f768d2d4fb89271b56c3a
Author: dwarning <dwarning>
Date:   Wed Jun 17 20:34:02 2020 +0200

    unify self-heating switch

commit c927c32541f8ee57ebce35066a5b0b10fdbf76af
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 17 18:41:15 2020 +0200

    qaSpec with ads run

commit d05eaa744e6abefdb2a2a874c6028e6f8b714ef1
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 17 17:38:50 2020 +0200

    added derivatives for NQS network

commit 88cf4bb92583cf8f02f5f65c23dde02a64f992e8
Author: dwarning <dwarning>
Date:   Wed Jun 17 13:24:03 2020 +0200

    allow SHE also without external temperature node

    prevent crash with rth=0

commit 716125334263ed3819241cdb9342b6cc4ce174b1
Merge: a46cb231a e2bb25b12
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 16 17:33:41 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit a46cb231a0
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 16 17:32:20 2020 +0200

    tmp node to gnd in HICUM if no SH

commit e2bb25b125
Author: dwarning <dwarning>
Date:   Mon Jun 15 08:54:50 2020 +0200

    qaSpec guess for ads

commit bbde282b51
Author: dwarning <dwarning>
Date:   Mon Jun 15 08:33:17 2020 +0200

    typo 1D

commit 4e6deec579
Merge: 5da1d7031 6fbbeb06d
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 14 19:58:33 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit 5da1d7031c
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 14 19:57:56 2020 +0200

    HICUMload transient part first review, small fixes

commit 96af16e673
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 14 18:53:49 2020 +0200

    gmin fix

commit 6fbbeb06d9
Author: dwarning <dwarning>
Date:   Sun Jun 14 11:05:12 2020 +0200

    complete device node request for temp node

commit eae118787e
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 13 21:52:32 2020 +0200

    fix hicumACload singular matrix bug

commit 2a1f47e1e5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 13 20:29:04 2020 +0200

    cleaned

commit 7e5fdae917
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 13 20:19:51 2020 +0200

    refactor gmin in HICUM

commit 7aadd9af4a
Merge: f55f613c2 595e46447
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 13 19:32:02 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit f55f613c24
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat Jun 13 19:31:39 2020 +0200

    added dual numbers include in ngspice/include

commit 595e464479
Author: dwarning <dwarning>
Date:   Fri Jun 12 19:13:26 2020 +0200

    introduce version parameter to prevent warnings in qa test

commit 147bf5eb4a
Author: dwarning <dwarning>
Date:   Fri Jun 12 17:16:48 2020 +0200

    use standard include path configuration for external cppduals

commit 7a41174b5e
Author: dwarning <dwarning>
Date:   Thu Jun 11 18:22:42 2020 +0200

    add ads for qa test

commit 3942fc48ce
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jun 11 17:40:13 2020 +0200

    added charges for SHE in HICUMacload

commit 12fa8a8cf7
Author: dwarning <dwarning>
Date:   Thu Jun 11 15:34:06 2020 +0200

    resolve confusing naming of instance parameter structure

commit 7578aec2a8
Author: dwarning <dwarning>
Date:   Thu Jun 11 15:29:40 2020 +0200

    introduce version parameter to prevent warnings in qa test

commit b401428cdd
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 10 18:17:44 2020 +0200

    minor cleaning

commit 5d28b97fb5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 7 16:46:21 2020 +0200

    added SHE stamps for DC currents in HICUMacload

commit 9737dc7a5b
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 7 16:36:36 2020 +0200

    HICUM acload initial review

commit 6eefe34d56
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 7 13:58:24 2020 +0200

    add real part of AC matrix

commit 55e14e62e7
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 7 13:20:12 2020 +0200

    dirty fix iavl

commit 99a21e9f61
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun Jun 7 12:15:39 2020 +0200

    some minor modificaitons, avalanche current problems

commit 99f8c9a9ed
Merge: 17898981c 6b9f5647c
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jun 5 10:27:08 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit 17898981cd
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri Jun 5 10:20:21 2020 +0200

    minor cleaning, fix derivative iavl

commit 6b9f5647ca
Author: dwarning <dwarning>
Date:   Thu Jun 4 18:23:10 2020 +0200

    first version for cmc qa check

commit 3f11d38774
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jun 4 16:37:09 2020 +0200

    implemented experimental rth direct evaluation

commit 40900da8bf
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Thu Jun 4 14:45:12 2020 +0200

    small correction

commit 7f1493bddb
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 3 19:25:35 2020 +0200

    minor changes, cleaning

commit 55367a44a5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 3 19:05:39 2020 +0200

    completed all del voltages

commit d32ff77aef
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 3 18:23:19 2020 +0200

    renaming variables for cleaner code

commit e4b4978368
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 3 18:17:49 2020 +0200

    adding derivatives of branches with respect to Vrth to the state vector

commit a6b39a749c
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 3 17:29:37 2020 +0200

    correct Temperature update

commit 55c33ad675
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Jun 3 17:21:31 2020 +0200

    before changing Temp in load

commit 7f7b31e5c0
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 2 20:01:07 2020 +0200

    fixing small bugs

commit 7555278074
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 2 19:39:48 2020 +0200

    fixed some stamps

commit 0d59e12518
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Jun 2 19:13:50 2020 +0200

    fixed avalanche

commit ee25c6ce42
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Jun 1 20:07:25 2020 +0200

    cleaned up

commit d61b510207
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Jun 1 19:18:45 2020 +0200

    hicumL2 load routine seems to be working, next ac?

commit 29a61f21e2
Merge: c94120cbf dcf4a4487
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Jun 1 14:32:39 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit c94120cbf9
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Jun 1 14:30:40 2020 +0200

    first hicum convergence with SH

commit dcf4a44871
Merge: c37a88bec c1444a06b
Author: dwarning <dwarning>
Date:   Mon Jun 1 10:57:42 2020 +0200

    Merge branch 'markus_dev' of ssh://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit c37a88bec8a12ab766ac1471a1dc452eabea41d3
Author: dwarning <dwarning>
Date:   Mon Jun 1 10:56:53 2020 +0200

    set the cppduals include folder above ngspice dir

commit c1444a06b606cde594d7ad8054df527cdd1d4f68
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun May 31 20:38:16 2020 +0200

    finish hicum SH review, next testing.

commit e3c194e050701139506ff821f931f7e14141129b
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun May 31 20:26:41 2020 +0200

    fixed some stamps, improved code readability, temp stamps corrected

commit 59c50d509572bf916021abc40e69a896f71e7ef6
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat May 30 20:37:28 2020 +0200

    fixed rbi stamp, convergence looks pretty good DC no SH

commit f7012280e626a885c5635a19db7025477def0f71
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sat May 30 17:12:37 2020 +0200

    fix rbi convergence

commit 326b29c4d86ff9f72fd2959419a8476f913cde48
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri May 29 16:54:30 2020 +0200

    started work on self heating

commit 4994feaa2b1b3d13873665b9383ae6e74ecd24d5
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Fri May 29 16:08:18 2020 +0200

    corrected rbi stamp...

commit 460e7ec04bd00563e4455a8868de1622dab10260
Author: mariok <mario.krattenmacher@web.de>
Date:   Wed May 20 11:22:01 2020 +0200

    more thermal stuff implemented

commit 194331867e3a92dd9740f72403f303a7121f5954
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue May 19 16:24:34 2020 +0200

    added HICUMtempCollPtr HICUMtempBasePtr HICUMtempEmitPtr

commit 697af41531cc193346b9fca1f2584b44f0dc0a09
Author: dwarning <dwarning>
Date:   Tue May 19 08:03:35 2020 +0200

    exchange hicum2temp file in VS project

commit 03750cd24e528119c69d69cf2fc188cfe7d7d334
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun May 17 20:20:00 2020 +0200

    ziwschenstand, checked code for maths errors

commit 418966c6e5625be535766ed3c6df7c124431a589
Author: mariok <mario.krattenmacher@web.de>
Date:   Wed May 13 10:25:49 2020 +0200

    can not call a function inside a comparision

commit abecd18651a5d490bbe6d75ad33bffa204df3322
Author: mariok <mario.krattenmacher@web.de>
Date:   Wed May 13 10:09:11 2020 +0200

    removed all buggs from hicumL2 to debug.

commit 1fe3cc8b12420b0a3e28fd25290d9d583abe02a9
Merge: afdffacd4 58f66c1d4
Author: mariok <mario.krattenmacher@web.de>
Date:   Wed May 13 07:30:56 2020 +0200

    Merge remote-tracking branch 'origin/markus_dev' into hicum2-mario

commit afdffacd4b54c992d9168e6babb9ff1e29b0f916
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue May 12 19:59:09 2020 +0200

    ac und pz load

commit 890ccc415fdba241e9964baa6c066e69ea8e7c7c
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue May 12 19:55:23 2020 +0200

    implemented hicum_diode as example

commit 63bf7113d4f46cb95c5c3e2b94f0e2e22ec81ea0
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue May 12 18:33:51 2020 +0200

    all temperature scaling equations done using dual numbers

commit 96c66dd6456693e2f89b4d62390e12160b6c5823
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue May 12 17:14:17 2020 +0200

    started dual numbers in hicum2temp and a transfer struct in hicum2defs

commit 58f66c1d460f8c7c80c23ab6a08f9ea370ab028f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue May 12 12:28:50 2020 +0200

    fix Vbe initialization

commit 35deffa742aea641e5ddc5077c3d78179f84d133
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue May 12 12:25:48 2020 +0200

    cleaned further

commit 304dd91f585aa5cc361ae996a9af2ff33043158a
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue May 12 12:15:52 2020 +0200

    cleaned up, small fixes, include Tf

commit 1d7da49e27b49f69449dffd164b5c3d079ca8f3f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue May 12 09:37:39 2020 +0200

    fixed bugs

commit 479c2a19eaabc4c7545b60d3aaeaf4ad702e19a3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon May 11 15:50:01 2020 +0200

    forgot Nan catcher

commit 5bbe0f9cf7022bff22bdf932f548e883ea2f79f0
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon May 11 15:48:03 2020 +0200

    bugfix Q_p calculation

commit 67857cf983e72243b3d6d37f882e4eadb20c0ecc
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon May 11 15:42:27 2020 +0200

    fixed derivatives and itf for case without newton iteration

commit d6ee2c206e3daf24fd52b9e58cf87961552c6b16
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon May 11 14:08:18 2020 +0200

    resolved some un-initialized variables

commit 76ed5cb36a9aca1ad2a1b081fa30d039d66b4e3b
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun May 10 20:48:38 2020 +0200

    finished clean

commit ba6e6d5e4990d048a34ab818e033363dd19f6869
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun May 10 18:48:24 2020 +0200

    added all remaining hicum l2 elements

commit 36244b809a3ea143aafc9bed62ea9376bc876f31
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Sun May 10 17:45:27 2020 +0200

    resolved Dietmar comments from email

commit eaa5be9716360a4003920ed94057e4fe92be9fdd
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue May 5 16:38:08 2020 +0200

    added base emitter recombination current and derivatives

commit 4318b7165bccd5e4fba632de02da96e5a64920bd
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue May 5 14:30:15 2020 +0200

    added initial conditions for all nodes, model converging again for
    simple modelcard

commit 3008c526bff4cba463c362dec2efc2b6c4e60b2a
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon May 4 19:00:31 2020 +0200

    removed QpT and testing only 1 OP

commit 9cb4c1546f70543b5e3b4060a600157e493c2534
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon May 4 18:37:52 2020 +0200

    icVBE and icVCE used for DC

commit 8a7369767551f3d5a2e18102ea0aae40a6dd8319
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon May 4 18:03:46 2020 +0200

    fixed dual number Q_0_hjei_vbe

commit 5783938b086e9b1f9bfb17e32aaf24aedf72f72e
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon May 4 16:30:41 2020 +0200

    reintroduced dtemp as instance parameter

commit 9350f3f3be710f195fb68b3f9f9ce30f937444ba
Author: dwarning <dwarning>
Date:   Sun May 3 17:25:12 2020 +0200

    Revert some namings

commit 197f6db83b7d5ad7a6bbb20acf2b884889bcd06c
Author: dwarning <dwarning>
Date:   Sat May 2 23:18:58 2020 +0200

    Adapt VS project to C++

commit af32f79641536edfa94cc683b6cede036969c667
Author: dwarning <dwarning>
Date:   Sat May 2 23:18:43 2020 +0200

    Skip NQS effekt and revert some namings

commit a995aa0ccec30cedf7c8088b5c6780abd0bab1c9
Author: dwarning <dwarning>
Date:   Sat May 2 23:18:27 2020 +0200

    Skip NQS effekt

commit d7295cbe78dd08ba99e95922e1a5a90de2b25666
Merge: 2502b57ee 6ca440e58
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Apr 29 19:04:32 2020 +0200

    Merge branch 'markus_dev' of https://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit 2502b57eee
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Wed Apr 29 19:03:26 2020 +0200

    added quests, derivative vciei changed to vbiei vbici

commit 6ca440e584
Author: dwarning <dwarning>
Date:   Wed Apr 29 09:35:12 2020 +0200

    add hicumL2.cpp instead of hicum2load.c in VS project

commit 6e98506a7f
Author: dwarning <dwarning>
Date:   Wed Apr 29 09:33:08 2020 +0200

    cmath seems not to have M_PI

commit d6332815b3
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Apr 28 20:58:35 2020 +0200

    derivatives it looking good

commit aaaace7247
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Apr 28 19:39:48 2020 +0200

    adding hicum derivatives like a mad-man

commit 2d8a3e3629
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Apr 28 18:44:46 2020 +0200

    added Q_pT and derivatives...fun

commit 50a3e372cf
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Apr 28 17:17:17 2020 +0200

    starting work on transfer current

commit 8fd70e2f15
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Tue Apr 28 13:01:18 2020 +0200

    added asks, found bug with ibci

commit 2baac89ae3
Merge: 97a0aa856 c897e60c8
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 27 20:47:06 2020 +0200

    Merge remote-tracking branch 'origin/hicum2-thermal' into markus_dev

commit c897e60c8b1e6df92564bf6e56ce9e3efc2bd40f
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon Apr 27 18:12:40 2020 +0200

    pointer in ask

commit 3b0551c544e542e10006b77bc0684b3075c874f7
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon Apr 27 17:36:19 2020 +0200

    two small bugfixes

commit b02c763ed1a1e1e53c095e8b88627a7d76e0954a
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon Apr 27 17:13:30 2020 +0200

    HICUM2ask done according to VA-Code

commit 97a0aa856b69806b3816a4db74e0b88a464b26a1
Merge: afbde8050 d86caadb0
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 27 16:22:32 2020 +0200

    Merge remote-tracking branch 'origin/hicum2-thermal' into markus_dev

commit afbde805009884b532fb9cad37827d2a4f6464ab
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 27 16:21:25 2020 +0200

    zwischenstand

commit d86caadb07482926593ce3cfc1dce53ebc009341
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 23 18:23:40 2020 +0200

    added nodes for NQS

commit 1b0cf0d08c7ca282dba8f1fbecf05b391324ef95
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 23 16:59:55 2020 +0200

    testing with and without self heating

commit 64c0c41180420b205b1eae1237634d31ffd2d1a5
Merge: 9da946bf2 0d0c6a080
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 23 16:29:18 2020 +0200

    Merge branch 'markus_dev' into hicum2-thermal

commit 0d0c6a0800681868ad8aa3f14367d1f81936e593
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 23 16:26:37 2020 +0200

    assigned the temperature derivates to me

commit 1b00fad771d6cd34b5bb3fd1fc5a1d23bcc87790
Merge: f5a1c35d8 dc7891f7b
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 23 14:16:32 2020 +0200

    Merge branch 'markus_dev' of ssh://git.code.sf.net/p/ngspice/ngspice into markus_dev

commit f5a1c35d803a2406e114133bb469705acd2fb7e5
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 23 14:14:40 2020 +0200

    removed dummdumm

commit dc7891f7b543b1f9651ed25e5632c631f402df49
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 19:16:36 2020 +0200

    added more junction caps, checklist and overview

commit 0dbf31bc739938eecc281656a3141085ffc4df42
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 19:00:16 2020 +0200

    derivatives rbi

commit 330d009fa684295f78f6b669fae2c663f7f4fe26
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 18:40:24 2020 +0200

    more derivatives avalanche current, ibcis

commit ce200d75e337c7cb684391b2d7556f6c2d8c8804
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 18:05:49 2020 +0200

    derivatives peripheral junction caps, diodes

commit 8ce9733f9176d5220c8db8c4deb322eb64f4ad1a
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 17:45:42 2020 +0200

    derivatives tunneling current

commit 806ff8013825cc154f11f2206644d0d8be825ecb
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 17:17:14 2020 +0200

    derivatives critical current

commit 8f49490cecf43ee22aecebcccb16752bc5a1728f
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 16:59:09 2020 +0200

    derivatives T_f0

commit 3164dbe594025e16d8dfbd1c50922dbcac70e62a
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 16:38:34 2020 +0200

    derivatives hole charge at low bias

commit b32bf6dd149a218e74af389f3a7bea9adcc89f22
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 16:27:38 2020 +0200

    zwischenstand

commit 84307c4acfb72aeb0cf9acbd0ca64223a58a20cb
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 16:19:25 2020 +0200

    zwischenstand

commit 0d94c5d56d86c52ab0638e095d7c6b816723929f
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon Apr 20 10:56:58 2020 +0200

    moved cppduals to system lib include

commit 9da946bf2d5beaa1a1e74c0465d78bfd079bc320
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon Apr 20 09:59:49 2020 +0200

    started derivatives of hicum2 minority charge

commit a2946e98a442e32fab493bcbd8d05ca934c20e20
Author: Markus Mueller <metroid120@googlemail.com>
Date:   Mon Apr 20 09:56:06 2020 +0200

    introduced dual numbers, ported hiucm2load to c++ hicumL2.cpp, boolean
    type protected by extern "C"

commit c7e5df27dbd5b74586d64c9404166e67a1c7af62
Author: mariok <mario.krattenmacher@web.de>
Date:   Thu Apr 16 14:44:41 2020 +0200

    DC runs with Ixf

commit 08a0e6a019957ba9c29ee96653254880b26c8c98
Author: mariok <mario.krattenmacher@web.de>
Date:   Wed Apr 15 18:15:26 2020 +0200

    gummel works with flsh = 1 and flnqs = 0

commit b83e05ee95c6d9771189e54ce6834519d71071c3
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue Apr 14 16:09:42 2020 +0200

    added test to makefile

commit 7d29a9a269cb405c71fd64249c5b439b87a64cc3
Author: mariok <mario.krattenmacher@web.de>
Date:   Tue Apr 14 10:06:27 2020 +0200

    test circuit and results

commit 14c46bc3bd3f2f2a4f333ef8e85e2d35dcfd8cc5
Author: mariok <mario.krattenmacher@web.de>
Date:   Mon Apr 13 18:12:06 2020 +0200

    cleaned renaming in all files

commit 67ddd98f7520d6cd729bbb5ca927859bb3d3f2b0
Author: dwarning <dwarning>
Date:   Wed Jan 29 13:08:02 2020 +0100

    rename

commit 9551b6df924e455bde48d5da3077dcd764d95761
Author: dwarning <dwarning>
Date:   Wed Jan 29 13:07:42 2020 +0100

    rename

commit 12bb866ba5d2481b09f6c9adc17ec21ed3038534
Author: dwarning <dwarning>
Date:   Wed Jan 29 13:06:45 2020 +0100

    rename

commit 414eeb4067249d3065181e308ffe7eb815a6f181
Author: dwarning <dwarning>
Date:   Tue Jan 28 22:18:08 2020 +0100

    clarify charge and capacitance implementation

commit c318ef15eefd0a0517cb35f4a4403a8e8cd00e17
Author: dwarning <dwarning>
Date:   Sat Jan 25 14:57:55 2020 +0100

    introduce first excess phase network and update to 2.4.0

commit 85c34cfb0f2b594febbd0adcb315ebb4e5499748
Author: dwarning <dwarning>
Date:   Wed Jan 22 18:16:54 2020 +0100

    VS update

commit 86ff2778f8ffcce688e8e08099801d920d6a3927
Author: dwarning <dwarning>
Date:   Wed Jan 22 18:16:29 2020 +0100

    OP infos

commit 1607f4d88c026fd573e19a16793208c48b025612
Author: dwarning <dwarning>
Date:   Wed Jan 22 18:16:19 2020 +0100

    OP infos

commit ca1e114922fecc11a4245a04f5639c11d539be8f
Author: dwarning <dwarning>
Date:   Wed Jan 22 18:16:11 2020 +0100

    OP infos

commit 408440d33b65741a7cd1171a9023f13cfb180e15
Author: dwarning <dwarning>
Date:   Tue Jan 21 11:25:56 2020 +0100

    some cleanings

commit 3364f6da87f79763344fd0f9ef705b521e23ee09
Author: dwarning <dwarning>
Date:   Tue Jan 14 09:55:58 2020 +0100

    VS update

commit 6fbefe4afa0fd1355eab636756ae592bad8b501f
Author: dwarning <dwarning>
Date:   Tue Jan 14 09:55:48 2020 +0100

    Ongoing derivations

commit 86521dd7c0e067644765e4de450b2eead9a1c24a
Author: dwarning <dwarning>
Date:   Tue Jan 14 09:02:52 2020 +0100

    VS update

commit ba5b106faeecc3170c3d018ec10b0a388c12e2cf
Author: dwarning <dwarning>
Date:   Tue Jan 14 09:01:30 2020 +0100

    Ongoing derivations

commit ea6254eca3b21fb3c7044eee00053cfce170034f
Author: dwarning <dwarning>
Date:   Sat Jan 11 17:17:21 2020 +0100

    Initial HICUM2 integration

commit 2bd0f1bdab6161ec21f790c4908590fcafa9b818
Author: dwarning <dwarning>
Date:   Mon Jan 6 00:11:48 2020 +0100

    Initial HICUM2 integration

commit 7d160f659e46021c0da882ea84ce4868ecd0acc0
Author: dwarning <dwarning>
Date:   Sun Jan 5 15:01:20 2020 +0100

    Initial HICUM2 integration

commit 420ca90e55bb77a3999527f25fa985146c6a1ef3
Author: dwarning <dwarning>
Date:   Sun Jan 5 15:00:06 2020 +0100

    Initial HICUM2 integration
pre-master-46
Markus Mueller 5 years ago
committed by Holger Vogt
parent
commit
6ff354c4a7
  1. 3
      .gitignore
  2. 11
      configure.ac
  3. 42
      examples/hicum2/hic2_ft.sp
  4. 24
      examples/hicum2/hic2_gain.sp
  5. 20
      examples/hicum2/hic2_gum.sp
  6. 18
      examples/hicum2/hic2_gum_inv.sp
  7. 31
      examples/hicum2/hic2_noise.sp
  8. 65
      examples/hicum2/hic2_noise_I.sp
  9. 65
      examples/hicum2/hic2_noise_V.sp
  10. 44
      examples/hicum2/hic2_noise_ver.sp
  11. 21
      examples/hicum2/hic2_out.sp
  12. 27
      examples/hicum2/hic2_tran.sp
  13. 175
      examples/hicum2/model-card-examples.lib
  14. 2
      src/Makefile.am
  15. 41
      src/include/cppduals/.appveyor.yml
  16. 18
      src/include/cppduals/.editorconfig
  17. 87
      src/include/cppduals/.gitlab-ci.yml
  18. 223
      src/include/cppduals/CMakeLists.txt
  19. 373
      src/include/cppduals/LICENSE.txt
  20. 354
      src/include/cppduals/README.md
  21. 2391
      src/include/cppduals/doc/Doxyfile.in
  22. 195
      src/include/cppduals/doc/DoxygenLayout.xml
  23. 12
      src/include/cppduals/doc/Greek_Epsilon_archaic.svg
  24. 2059
      src/include/cppduals/doc/customdoxygen.css
  25. BIN
      src/include/cppduals/doc/favicon.ico
  26. 20
      src/include/cppduals/doc/footer.html
  27. 200
      src/include/cppduals/doc/gitlab-release
  28. 57
      src/include/cppduals/doc/header.html
  29. 510
      src/include/cppduals/duals/arch/AVX/ComplexDual.h
  30. 548
      src/include/cppduals/duals/arch/AVX/Dual.h
  31. 229
      src/include/cppduals/duals/arch/SSE/ComplexDual.h
  32. 459
      src/include/cppduals/duals/arch/SSE/Dual.h
  33. 1384
      src/include/cppduals/duals/dual
  34. 774
      src/include/cppduals/duals/dual_eigen
  35. BIN
      src/include/cppduals/paper/benchmark.png
  36. 86
      src/include/cppduals/paper/paper.bib
  37. 164
      src/include/cppduals/paper/paper.md
  38. 240
      src/include/cppduals/tests/CMakeLists.txt
  39. 88
      src/include/cppduals/tests/bench_dual.cpp
  40. 398
      src/include/cppduals/tests/bench_eigen.cpp
  41. 74
      src/include/cppduals/tests/bench_example.cpp
  42. 109
      src/include/cppduals/tests/bench_fmt.cpp
  43. 244
      src/include/cppduals/tests/bench_gemm.cpp
  44. 43
      src/include/cppduals/tests/example.cpp
  45. 472
      src/include/cppduals/tests/gold-riick.bench_dual.json
  46. 1160
      src/include/cppduals/tests/gold-riick.bench_eigen.json
  47. 142
      src/include/cppduals/tests/runbench.sh
  48. 122
      src/include/cppduals/tests/sandbox.cpp
  49. 208
      src/include/cppduals/tests/test_1.cpp
  50. 1108
      src/include/cppduals/tests/test_dual.cpp
  51. 549
      src/include/cppduals/tests/test_eigen.cpp
  52. 215
      src/include/cppduals/tests/test_expm.cpp
  53. 213
      src/include/cppduals/tests/test_fmt.cpp
  54. 215
      src/include/cppduals/tests/test_funcs.cpp
  55. 402
      src/include/cppduals/tests/test_packets.cpp
  56. 119
      src/include/cppduals/tests/test_solve.cpp
  57. 342
      src/include/cppduals/tests/test_vectorize.cpp
  58. 106
      src/include/cppduals/tests/type_name.hpp
  59. 17
      src/include/cppduals/thirdparty/CMakeLists-gt.txt.in
  60. 220
      src/include/cppduals/thirdparty/CMakeLists.txt
  61. 4
      src/include/ngspice/bool.h
  62. 7
      src/include/ngspice/cktdefs.h
  63. 2
      src/spicelib/devices/Makefile.am
  64. 8
      src/spicelib/devices/dev.c
  65. 1
      src/spicelib/devices/dio/dioload.c
  66. 33
      src/spicelib/devices/hicum2/Makefile.am
  67. 304
      src/spicelib/devices/hicum2/hicum2.c
  68. 645
      src/spicelib/devices/hicum2/hicum2acld.c
  69. 251
      src/spicelib/devices/hicum2/hicum2ask.c
  70. 221
      src/spicelib/devices/hicum2/hicum2conv.c
  71. 1180
      src/spicelib/devices/hicum2/hicum2defs.h
  72. 27
      src/spicelib/devices/hicum2/hicum2ext.h
  73. 51
      src/spicelib/devices/hicum2/hicum2getic.c
  74. 85
      src/spicelib/devices/hicum2/hicum2init.c
  75. 20
      src/spicelib/devices/hicum2/hicum2init.h
  76. 11
      src/spicelib/devices/hicum2/hicum2itf.h
  77. 460
      src/spicelib/devices/hicum2/hicum2mask.c
  78. 634
      src/spicelib/devices/hicum2/hicum2mpar.c
  79. 293
      src/spicelib/devices/hicum2/hicum2noise.c
  80. 70
      src/spicelib/devices/hicum2/hicum2param.c
  81. 758
      src/spicelib/devices/hicum2/hicum2pzld.c
  82. 863
      src/spicelib/devices/hicum2/hicum2setup.c
  83. 73
      src/spicelib/devices/hicum2/hicum2soachk.c
  84. 43
      src/spicelib/devices/hicum2/hicum2trunc.c
  85. 3350
      src/spicelib/devices/hicum2/hicumL2.cpp
  86. 23
      src/spicelib/devices/hicum2/hicumL2.hpp
  87. 521
      src/spicelib/devices/hicum2/hicumL2temp.cpp
  88. 17
      src/spicelib/devices/hicum2/hicumL2temp.hpp
  89. 6
      src/spicelib/parser/inp2q.c
  90. 2
      src/spicelib/parser/inpdomod.c
  91. 1
      tests/Makefile.am
  92. 686
      tests/bin/ads.pm
  93. 2
      tests/bin/ngspice.pm
  94. 17
      tests/bin/run_cmc_check
  95. 37
      tests/hicum2/FG.cir
  96. 112
      tests/hicum2/FG.out
  97. 34
      tests/hicum2/FG_sh.cir
  98. 15
      tests/hicum2/Makefile.am
  99. 41
      tests/hicum2/npn/parameters/compare_para.pl
  100. 125
      tests/hicum2/npn/parameters/npn_1D

3
.gitignore

@ -76,8 +76,11 @@ Makefile.in
# Visual Studio user options files # Visual Studio user options files
**/*.vcxproj.user **/*.vcxproj.user
.vscode/
src/frontend/parse-bison.c src/frontend/parse-bison.c
src/frontend/parse-bison.h src/frontend/parse-bison.h
src/spicelib/parser/inpptree-parser.c src/spicelib/parser/inpptree-parser.c
src/spicelib/parser/inpptree-parser.h src/spicelib/parser/inpptree-parser.h
# Visual Studio Code user options files
.vscode/

11
configure.ac

@ -35,6 +35,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
ext_CFLAGS="${CFLAGS+yes}" ext_CFLAGS="${CFLAGS+yes}"
AC_PROG_CC AC_PROG_CC
AC_PROG_CXX
AX_PROG_CC_FOR_BUILD AX_PROG_CC_FOR_BUILD
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
@ -43,6 +44,8 @@ AC_SUBST([AM_CPPFLAGS], ['-I. -I$(srcdir) -I$(top_builddir)/src/include'])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
# Package Options # Package Options
# --------------- # ---------------
@ -683,6 +686,7 @@ AC_ARG_ENABLE([rpath],
] ]
) )
if test "x$_use_rpath" = xyes ; then if test "x$_use_rpath" = xyes ; then
# Try to figure out if we need -Rpath for finding X11 libs # Try to figure out if we need -Rpath for finding X11 libs
# at runtime. Why autoconf doesn't already do this, I don't # at runtime. Why autoconf doesn't already do this, I don't
@ -767,6 +771,11 @@ esac
AM_CONDITIONAL([NO_X], [test "x$has_no_x" = xtrue]) AM_CONDITIONAL([NO_X], [test "x$has_no_x" = xtrue])
AM_CONDITIONAL([NO_HELP], [test "x$has_no_help" = xtrue]) AM_CONDITIONAL([NO_HELP], [test "x$has_no_help" = xtrue])
# Additional libs of hicum group
AC_CHECK_LIB(stdc++, main, XTRALIBS="$XTRALIBS -lstdc++",,)
AC_SUBST(XTRALIBS, $XTRALIBS)
LIBS="$LIBS $XTRALIBS"
# enabling making of the old and outdated applications # enabling making of the old and outdated applications
# ngsconvert ngproc2mod ngmultidec ngmakeidx nghelp # ngsconvert ngproc2mod ngmultidec ngmakeidx nghelp
@ -1239,6 +1248,7 @@ AC_CONFIG_FILES([Makefile
src/spicelib/devices/isrc/Makefile src/spicelib/devices/isrc/Makefile
src/spicelib/devices/hfet1/Makefile src/spicelib/devices/hfet1/Makefile
src/spicelib/devices/hfet2/Makefile src/spicelib/devices/hfet2/Makefile
src/spicelib/devices/hicum2/Makefile
src/spicelib/devices/hisim2/Makefile src/spicelib/devices/hisim2/Makefile
src/spicelib/devices/hisimhv1/Makefile src/spicelib/devices/hisimhv1/Makefile
src/spicelib/devices/hisimhv2/Makefile src/spicelib/devices/hisimhv2/Makefile
@ -1315,6 +1325,7 @@ AC_CONFIG_FILES([Makefile
tests/filters/Makefile tests/filters/Makefile
tests/general/Makefile tests/general/Makefile
tests/hfet/Makefile tests/hfet/Makefile
tests/hicum2/Makefile
tests/hisim/Makefile tests/hisim/Makefile
tests/hisimhv1/Makefile tests/hisimhv1/Makefile
tests/hisimhv2/Makefile tests/hisimhv2/Makefile

42
examples/hicum2/hic2_ft.sp

@ -0,0 +1,42 @@
HICUM2v2.40 Test ft=f(Ic) Vce=1V
vce 1 0 dc 1.0
vgain 1 c dc 0.0
f 0 2 vgain -2
l 2 b 1g
c 2 0 1g
ib 0 b dc 0.0 ac 1.0
ic 0 c 0.001
Q1 C B 0 hicumL2V2p40
.control
let run = 0
let ft_runs = 9
set curplot=new $ create a new plot
set curplotname=ft_plot
set curplottitle="HICUM2v2.40 ft = f(Ic)"
set scratch=$curplot $ store its name to 'scratch'
setplot $scratch $ make 'scratch' the active plot
let ft=unitvec(ft_runs) $ create a vector in plot 'scratch' to store ft data
let ic=unitvec(ft_runs) $ create a vector in plot 'scratch' to store ic data
foreach myic 1e-03 3e-03 6e-03 9e-03 14e-03 21e-03 27e-03 33e-3 40e-03
alter ic = $myic
op
print all
ac dec 100 1Meg 800g
meas ac freq_at when vdb(vgain#branch)=0
set run ="$&run" $ create a variable from the vector
set dt = $curplot $ store the current plot to dt
setplot $scratch $ make 'scratch' the active plot
let ic[run] = $myic $ store ic to vector ft in plot 'scratch'
let ft[run] = {$dt}.freq_at $ store ft to vector ft in plot 'scratch'
setplot $dt $ go back to the previous plot
let run = run + 1
end
setplot unknown1
plot ft vs ic xlog
.endc
.include model-card-examples.lib
.end

24
examples/hicum2/hic2_gain.sp

@ -0,0 +1,24 @@
HICUM2v2.40 AC gain Test h21 = f(Ic) Vce=1V
vce 1 0 dc 1.0
vgain 1 c dc 0.0
f 0 2 vgain -2
l 2 b 1g
c 2 0 1g
ib 0 b dc 0.0 ac 1.0
ic 0 c 0.001
Q1 C B 0 hicumL2V2p40
.control
foreach myic 2e-03 4e-03 7e-03 9e-03 18e-03 33e-3
alter ic = $myic
op
print all
ac dec 10 1Meg 800g
end
plot abs(ac1.vgain#branch) abs(ac2.vgain#branch) abs(ac3.vgain#branch) abs(ac4.vgain#branch) abs(ac5.vgain#branch) abs(ac6.vgain#branch) ylimit 0.1 300 loglog
.endc
.include model-card-examples.lib
.end

20
examples/hicum2/hic2_gum.sp

@ -0,0 +1,20 @@
HICUM2v2.40 Gummel Test Ic,b,s=f(Vc,Ib) Vce=1V
VB B 0 1.2
VC C 0 1.0
VS S 0 0.0
Q1 C B 0 S hicumL2V2p40
.control
option gmin=1e-14
dc vb 0.2 1.2 0.01
*plot i(vc) i(vb) i(vs)
*gnuplot fgum i(vc) i(vb) i(vs) xlimit 0.2 1.2 ylog ylimit 1e-12 0.1
plot abs(i(vc)) abs(i(vb)) abs(i(vs)) xlimit 0.2 1.2 ylog ylimit 1e-14 0.1
plot abs(i(vc))/abs(i(vb)) vs abs(i(vc)) xlog xlimit 1e-09 100e-3; ylimit 0 500
.endc
.include model-card-examples.lib
.end

18
examples/hicum2/hic2_gum_inv.sp

@ -0,0 +1,18 @@
HICUM2v2.40 Gummel Test invers Ie,b,s=f(Ve,Ib) Vec=1V
VB B 0 1.2
VE E 0 1.0
VS S 0 0.0
Q1 0 B E S hicumL2V2p40
.control
dc vb 0.2 1.2 0.01
*plot i(ve) i(vb) i(vs)
plot abs(i(ve)) abs(i(vb)) abs(i(vs)) xlimit 0.2 1.2 ylog ylimit 1e-12 0.1
plot abs(i(ve))/abs(i(vb)) vs abs(i(ve)) xlog xlimit 1e-06 100e-3 ylimit 0 50
.endc
.include model-card-examples.lib
.end

31
examples/hicum2/hic2_noise.sp

@ -0,0 +1,31 @@
HICUM2v2.40 Noise Test
vcc 4 0 26
vin 1 0 ac 1
ccouple 1 b 1
ibias 0 b 100uA
rload 4 c 1k noisy=0
q1 c b 0 0 hicumL2V2p40
.include model-card-examples.lib
.control
op
print all
echo
noise v(c) vin dec 10 10 10G 1
setplot
setplot noise1
plot ally
plot inoise_spectrum onoise_spectrum loglog
setplot noise2
print all
echo
print inoise_total onoise_total
.endc
.end

65
examples/hicum2/hic2_noise_I.sp

@ -0,0 +1,65 @@
HICUM2v2.40 Noise Current Test
* _______
* _|_ _|_
* /// / _ \
* \/ \/ I1
* /\_/\
* R1 \___/
* _/\ __|
* | \/ _|
* |____|'
* B |`->
* _|_ E
* /VIN\
* \___/
* _|_
* ///
*
*
vin E 0 DC 0.0 ac 1.0u
I1 0 C 1uA
R1 C B 1000k noisy=0
q1 C B E hicumL2V2p40
.include model-card-examples.lib
.control
setplot new
let V1u = 0*vector(81)
let V10u = 0*vector(81)
let V100u = 0*vector(81)
let V1000u = 0*vector(81)
op
noise v(C) vin dec 10 1 100Meg 1
destroy
let unknown1.V1u = sqrt(v(onoise_spectrum))*1u
alter I1 dc = 10u
op
noise v(C) vin dec 10 1 100Meg 1
destroy
let unknown1.V10u = sqrt(v(onoise_spectrum))*1u
alter I1 dc = 100u
op
noise v(C) vin dec 10 1 100Meg 1
destroy
let unknown1.V100u = sqrt(v(onoise_spectrum))*1u
alter I1 dc = 1000u
op
noise v(C) vin dec 10 1 100Meg 1
destroy
let unknown1.V1000u = sqrt(v(onoise_spectrum))*1u
set pensize = 2
plot unknown1.V1u unknown1.V10u unknown1.V100u unknown1.V1000u vs frequency loglog title LM394NoiseCurrent
echo " ... done."
.endcontrol
.end

65
examples/hicum2/hic2_noise_V.sp

@ -0,0 +1,65 @@
HICUM2v2.40 Noise Voltage Test
* _______
* _|_ _|_
* /// / _ \
* \/ \/ I1
* /\_/\
* \___/
* _______|
* | _|
* |____|'
* B |`->
* _|_ E
* /VIN\
* \___/
* _|_
* ///
*
*
vin E 0 DC 0.0 ac 1.0u
I1 0 B 1uA
q1 B B E hicumL2V2p40
.include model-card-examples.lib
.control
setplot new
let V1u = 0*vector(81)
let V10u = 0*vector(81)
let V100u = 0*vector(81)
let V1000u = 0*vector(81)
op
noise v(B) vin dec 10 1 100Meg 1
destroy
let unknown1.V1u = sqrt(v(onoise_spectrum))
alter I1 dc = 10u
op
noise v(B) vin dec 10 1 100Meg 1
destroy
let unknown1.V10u = sqrt(v(onoise_spectrum))
alter I1 dc = 100u
op
noise v(B) vin dec 10 1 100Meg 1
destroy
let unknown1.V100u = sqrt(v(onoise_spectrum))
alter I1 dc = 1000u
op
noise v(B) vin dec 10 1 100Meg 1
destroy
let unknown1.V1000u = sqrt(v(onoise_spectrum))
set pensize = 2
plot unknown1.V1u unknown1.V10u unknown1.V100u unknown1.V1000u vs frequency loglog title HICUM_NoiseVoltage
echo " ... done."
.endcontrol
.end

44
examples/hicum2/hic2_noise_ver.sp

@ -0,0 +1,44 @@
HICUM2v2.40 Noise Voltage Test
* _______
* _|_ _|_
* /// / _ \
* \/ \/ I1
* /\_/\
* \___/
* _______|
* | _|
* |____|'
* B |`->
* _|_ E
* /VIN\
* \___/
* _|_
* ///
*
*
vin E 0 DC 0.0 ac 1.0u
I1 0 B 25mA
q1 B B E hicumL2V2p40
.include model-card-examples.lib
.control
setplot new
let V1u = 0*vector(81)
op
noise v(B) vin dec 10 1 100Meg 1
destroy
*let unknown1.V1u = sqrt(v(onoise_spectrum))
let unknown1.V1u = v(onoise_spectrum)
set pensize = 2
plot unknown1.V1u vs frequency loglog title HICUM_NoiseVoltage
echo " ... done."
.endcontrol
.end

21
examples/hicum2/hic2_out.sp

@ -0,0 +1,21 @@
HICUM2v2.40 Output Test Ic=f(Vc,Ib)
IB 0 B 1u
VC C 0 1.8
VS S 0 0.0
Q1 C B 0 S tj hicumL2V2p40
.control
dc vc 0.0 1.8 0.01 ib 10u 100u 10u
plot -i(vc)
reset
altermod @hicumL2V2p40[flsh]=1
dc vc 0.0 1.8 0.01 ib 1u 10u 1u
plot -i(vc)
plot v(tj)
.endc
.include model-card-examples.lib
.end

27
examples/hicum2/hic2_tran.sp

@ -0,0 +1,27 @@
HICUM2v2.40 Amplifier in Time Domain
vcc 2 0 2.5
*vin 1 0 ac 1 dc 0 sin 0 25m 1G
vin 1 0 ac 1 dc 0 pulse 0 50m 0 5p 5p 4n 8n
rs 1 in 50
c1 in b 1n
r1 2 c 180
r2 c b 5k
q1 c b 0 0 hicuml2v2p40
c2 c out 100p
r3 out 0 1k
.ic v(c)=0.9
.control
option method=gear
op
print all
ac dec 10 1Meg 9.9g
plot vdb(out)
tran 2p 200n
plot v(in) v(out)
.endc
.include model-card-examples.lib
.end

175
examples/hicum2/model-card-examples.lib

@ -0,0 +1,175 @@
* Example parameter test set
.model hicumL2V2p40 npn level=8
*
*Transfer current
+ c10 = 9.074e-030
+ qp0 = 1.008e-013
+ ich = 0
+ hf0 = 40
+ hfe = 10.01
+ hfc = 20.04
+ hjei = 3.382
+ ahjei = 3
+ rhjei = 2
+ hjci = 0.2
*
*Base-Emitter diode currents
+ ibeis = 1.328e-019
+ mbei = 1.027
+ ireis = 1.5e-015
+ mrei = 2
+ ibeps = 1.26e-019
+ mbep = 1.042
+ ireps = 1.8e-015
+ mrep = 1.8
+ mcf = 1
*
*Transit time for excess recombination current at b-c barrier
+ tbhrec = 1e-010
*
*Base-Collector diode currents
+ ibcis = 4.603e-017
+ mbci = 1.15
+ ibcxs = 0
+ mbcx = 1
*
*Base-Emitter tunneling current
+ ibets = 0.02035
+ abet = 24
+ tunode = 1
*
*Base-Collector avalanche current
+ favl = 18.96
+ qavl = 5.092e-014
+ alfav = -0.0024
+ alqav = -0.0006284
+ kavl = 0.0
+ alkav = 0.0
*
*Series resistances
+ rbi0 = 4.444
+ rbx = 2.568
+ fgeo = 0.7409
+ fdqr0 = 0
+ fcrbi = 0
+ fqi = 1
+ re = 1.511
+ rcx = 2.483
*
*Substrate transistor
+ itss = 1.143e-017
+ msf = 1.056
+ iscs = 4.60106e-015
+ msc = 1.018
+ tsf = 0
*
*Intra-device substrate coupling
+ rsu = 500
+ csu = 6.4e-014
*
*Depletion Capacitances
+ cjei0 = 8.869e-015
+ vdei = 0.714
+ zei = 0.2489
+ ajei = 1.65
+ cjep0 = 2.178e-015
+ vdep = 0.8501
+ zep = 0.2632
+ ajep = 1.6
+ cjci0 = 3.58e-015
+ vdci = 0.8201
+ zci = 0.2857
+ vptci = 1.79
+ cjcx0 = 6.299e-015
+ vdcx = 0.8201
+ zcx = 0.2863
+ vptcx = 1.977
+ fbcpar = 0.3
+ fbepar = 1
+ cjs0 = 2.6e-014
+ vds = 0.9997
+ zs = 0.4295
+ vpts = 100
+ cscp0 = 1.4e-014
+ vdsp = 0
+ zsp = 0.35
+ vptsp = 4
*
*Diffusion Capacitances
+ t0 = 2.089e-013
+ dt0h = 8e-014
+ tbvl = 8.25e-014
+ tef0 = 3.271e-013
+ gtfe = 3.548
+ thcs = 5.001e-012
+ ahc = 0.05
+ fthc = 0.7
+ rci0 = 9.523
+ vlim = 0.6999
+ vces = 0.01
+ vpt = 2
+ aick = 1e-3
+ delck = 2
+ tr = 0
+ vcbar = 0.04
+ icbar = 0.01
+ acbar = 1.5
*
*Isolation Capacitances
+ cbepar = 2.609e-014
+ cbcpar = 1.64512e-014
*
*Non-quasi-static Effect
+ flnqs = 0
+ alqf = 0.166667
+ alit = 0.333333
*
*Noise
+ kf = .3e-16
+ af = .75
+ cfbe = -1
+ flcono = 0
+ kfre = 0.0
+ afre = 2.0
*
*Lateral Geometry Scaling (at high current densities)
+ latb = 0.0
+ latl = 0.0
*
*Temperature dependence
+ vgb = 0.91
+ alt0 = 0.004
+ kt0 = 6.588e-005
+ zetaci = 0.58
+ alvs = 0.001
+ alces = -0.2286
+ zetarbi = 0.3002
+ zetarbx = 0.06011
+ zetarcx = -0.02768
+ zetare = -0.9605
+ zetacx = 0
+ vge = 1.17
+ vgc = 1.17
+ vgs = 1.049
+ f1vg = -0.000102377
+ f2vg = 0.00043215
+ zetact = 5
+ zetabet = 4.892
+ alb = 0
+ dvgbe = 0
+ zetahjei = -0.5
+ zetavgbe = 0.7
*
*Self-Heating
+ flsh = 0
+ rth = 1113.4
+ cth = 6.841e-012
+ zetarth = 0
+ alrth = 0.002
*
*Compatibility with V2.1
+ flcomp = 2.3
*
*Circuit simulator specific parameters
+ tnom = 26.85
*+ dt = 0

2
src/Makefile.am

@ -73,6 +73,7 @@ DYNAMIC_DEVICELIBS = \
spicelib/devices/isrc/libisrc.la \ spicelib/devices/isrc/libisrc.la \
spicelib/devices/hfet1/libhfet.la \ spicelib/devices/hfet1/libhfet.la \
spicelib/devices/hfet2/libhfet2.la \ spicelib/devices/hfet2/libhfet2.la \
spicelib/devices/hicum2/libhicum2.la \
spicelib/devices/hisim2/libhisim2.la \ spicelib/devices/hisim2/libhisim2.la \
spicelib/devices/hisimhv1/libhisimhv1.la \ spicelib/devices/hisimhv1/libhisimhv1.la \
spicelib/devices/hisimhv2/libhisimhv2.la \ spicelib/devices/hisimhv2/libhisimhv2.la \
@ -581,6 +582,7 @@ libngspice_la_LIBADD += \
libngspice_la_CFLAGS = -shared libngspice_la_CFLAGS = -shared
libngspice_la_LDFLAGS = -shared libngspice_la_LDFLAGS = -shared
libngspice_la_LDFLAGS += -lstdc++
if SHWIN if SHWIN
libngspice_la_LDFLAGS += -Wl,--output-def=ngspice.def -Wl,--out-implib=ngspice.dll.a libngspice_la_LDFLAGS += -Wl,--output-def=ngspice.def -Wl,--out-implib=ngspice.dll.a

41
src/include/cppduals/.appveyor.yml

@ -0,0 +1,41 @@
version: 0.2.{build}
clone_folder: c:\projects\cppduals
clone_depth: 3
image:
#- Visual Studio 2013
#- Visual Studio 2015
- Visual Studio 2017
configuration:
- Release
#- Debug # someone with a debugger please investigate this :)
# Do not build feature branch with open Pull Requests
skip_branch_with_pr: true
# skip unsupported combinations
init:
- echo %APPVEYOR_BUILD_WORKER_IMAGE%
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" ( set generator="Visual Studio 12 2013" )
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( set generator="Visual Studio 14 2015" )
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set generator="Visual Studio 15 2017" )
- echo %generator%
before_build:
- cmd: |-
mkdir build
cd build
cmake --version
cmake .. -G %generator% -DCPPDUALS_TESTING=ON
pwd
ls
build:
project: c:\projects\cppduals\build\cppduals.sln
verbosity: minimal
# parallel: true
test_script:
- pwd
- ctest -C Debug -VV

18
src/include/cppduals/.editorconfig

@ -0,0 +1,18 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
[*.{cpp,hpp,h}]
indent_style = space
indent_size = 2
[{duals/**,tests/**}]
trim_trailing_whitespace = true
[CMakeLists.txt]
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

87
src/include/cppduals/.gitlab-ci.yml

@ -0,0 +1,87 @@
#image: ubuntu:19.04
image: fedora:30
variables:
GIT_DEPTH: 3
CTEST_OUTPUT_ON_FAILURE: y
stages:
- build
- test
- cover
- publish
before_script:
#- apt-get update --yes
#- apt-get install --yes cmake g++ git doxygen lcov graphviz
- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
build:
stage: build
# variables:
# CC: clang
# CXX: clang++
script:
- echo $CXX
- cmake -Bbuild -H. -DCPPDUALS_TESTING=ON
- cmake --build build
- cmake -Bbuild-latest -H. -DCPPDUALS_TESTING=ON -DCPPDUALS_EIGEN_LATEST=ON
- cmake --build build-latest
artifacts:
expire_in: 1 week
paths:
- build
- build-latest
test:
stage: test
script:
- cmake --build build --target test
- cmake --build build-latest --target test
dependencies:
- build
cover:
script:
- cmake -Bbuild-cov -H. -DCODE_COVERAGE=ON -DCPPDUALS_TESTING=ON
- cmake --build build-cov --target cov
- cmake --build build-cov --target cov-html
coverage: '/Total:|\w*\d+\.\d+/'
artifacts:
expire_in: 1 day
paths:
- build-cov
only:
- merge_requests
pages:
script:
- cmake -Bbuild -H. -DCODE_COVERAGE=ON -DCPPDUALS_TESTING=ON
- cmake --build build --target cppduals_docs
- cmake --build build --target cov-html
- mv build/docs public/
- mv build/coverage public/
coverage: '/Total:|\w*\d+\.\d+/'
artifacts:
paths:
- public
only:
- master
publish:
stage: publish
dependencies:
- build
environment:
name: publish
only:
- /^v\d+\.\d+\.\d+$/
except:
- branches
before_script:
- dnf install -y python3-requests
script:
# - ln -s cppduals-h-${CI_BUILD_TAG#v} .
# - tar czvhf cppduals-h-${CI_BUILD_TAG#v}.tgz cppduals-h-${CI_BUILD_TAG#v}/duals cppduals-h-${CI_BUILD_TAG#v}/CMakeLists.txt
- tar czvf cppduals-h-${CI_BUILD_TAG#v}.tgz duals CMakeLists.txt
- ./doc/gitlab-release --message "Release ${CI_BUILD_TAG}" cppduals-h-${CI_BUILD_TAG#v}.tgz

223
src/include/cppduals/CMakeLists.txt

@ -0,0 +1,223 @@
#
# CMake for cppduals
#
cmake_minimum_required (VERSION 3.1)
project (cppduals
VERSION 0.3.1
LANGUAGES C CXX
)
include (GNUInstallDirs)
set (CMAKE_CXX_STANDARD 11 CACHE STRING "Which C++ standard to test against.")
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (CMAKE_DISABLE_IN_SOURCE_BUILD ON)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
message (STATUS "Configuring cppduals for standalone build")
set (CPPDUALS_STANDALONE TRUE)
elseif ()
message (STATUS "Configuring cppduals for subproject build")
set (CPPDUALS_STANDALONE FALSE)
endif ()
if (CPPDUALS_STANDALONE AND
NOT CMAKE_CONFIGURATION_TYPES AND
NOT CMAKE_NO_BUILD_TYPE AND
NOT CMAKE_BUILD_TYPE
)
message (STATUS "Setting build type to 'RelWithDebInfo' since none specified")
set_property (CACHE CMAKE_BUILD_TYPE PROPERTY VALUE RelWithDebInfo)
set_property (CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo"
)
endif ()
if (CPPDUALS_STANDALONE AND
CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set (CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install"
CACHE PATH "cppduals installation directory"
FORCE
)
message (STATUS "No install prefix specified; using '${CMAKE_INSTALL_PREFIX}'")
endif ()
set_property (CACHE CMAKE_CXX_STANDARD PROPERTY STRINGS 11 14 17 20)
option (CPPDUALS_TESTING "Enable testing" OFF)
option (CPPDUALS_BENCHMARK "Enable benchmarking" OFF)
option (CPPDUALS_EIGEN_LATEST "Eigen latest" OFF)
option (CPPDUALS_USE_LIBCXX "When testing use flags for libc++" OFF)
set (EIGEN3_INCLUDE_DIRS "" CACHE PATH "Path to Eigen includes" )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wpedantic")
endif ()
if (CPPDUALS_BENCHMARK)
set (CPPDUALS_TESTING ON)
endif (CPPDUALS_BENCHMARK)
if (CPPDUALS_USE_LIBCXX)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options ("-stdlib=libc++")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ ") # -lc++abi
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
# this is unfinished...
set (CPPDUALS_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
message (WARNING "libc++ header path must be manually specified using CMAKE_CXX_FLAGS")
list (APPEND CPPDUALS_CXX_LINKER_FLAGS -nodefaultlibs)
list (APPEND CPPDUALS_CXX_LIBRARIES c++)
else ()
message(FATAL_ERROR "-DCPPDUALS_USE_LIBCXX:BOOL=ON is not supported for this compiler")
endif ()
endif (CPPDUALS_USE_LIBCXX)
#
# Primary Library Target
#
add_library (cppduals_duals INTERFACE)
target_include_directories (cppduals_duals
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set_target_properties (cppduals_duals
PROPERTIES
EXPORT_NAME duals
)
add_library (cppduals::duals ALIAS cppduals_duals)
#
# Build external dependencies for testing & benchmarking
#
if (CPPDUALS_TESTING)
cmake_minimum_required (VERSION 3.10) # need gtest_discover_tests
file (MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/thirdparty")
# generator name
if (NOT "${CMAKE_EXTRA_GENERATOR}" STREQUAL "")
set (GENERATOR_STRING "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
else ()
set (GENERATOR_STRING "${CMAKE_GENERATOR}")
endif ()
# configure the thirdparty build dir
execute_process (
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/thirdparty"
COMMAND ${CMAKE_COMMAND} "-G${GENERATOR_STRING}"
"-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
"-DCPPDUALS_BENCHMARK=${CPPDUALS_BENCHMARK}"
"-DCPPDUALS_EIGEN_LATEST=${CPPDUALS_EIGEN_LATEST}"
"-DCPPDUALS_USE_LIBCXX=${CPPDUALS_USE_LIBCXX}"
"${PROJECT_SOURCE_DIR}/thirdparty"
RESULT_VARIABLE DEPS_CONFIG_RESULT
)
if (DEPS_CONFIG_RESULT)
message (FATAL_ERROR "Configuring dependencies failed: ${DEPS_CONFIG_RESULT}")
endif ()
# build the thirdparty
message ("***************************************************************")
message ("** Building '${PROJECT_BINARY_DIR}/thirdparty'...")
message ("***************************************************************")
execute_process (
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/thirdparty"
COMMAND "${CMAKE_COMMAND}" --build .
RESULT_VARIABLE DEPS_BUILD_RESULT
)
message ("***************************************************************")
message ("*** Building thirdparty/ done.")
message ("***************************************************************")
if (DEPS_BUILD_RESULT)
message ("***************************************************************")
message (FATAL_ERROR "Building dependencies failed: ${DEPS_BUILD_RESULT}")
message ("***************************************************************")
endif ()
add_subdirectory (thirdparty)
endif ()
#
# Code Coverage Configuration
#
add_library (cppduals_coverage_config INTERFACE)
option (CODE_COVERAGE "Enable coverage reporting" OFF)
if (CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
# Add required flags (GCC & LLVM/Clang)
target_compile_options (cppduals_coverage_config INTERFACE
-O0 # no optimization
-g # generate debug info
--coverage # sets all required flags
)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
target_link_options (cppduals_coverage_config INTERFACE --coverage)
else ()
target_link_libraries (cppduals_coverage_config INTERFACE --coverage)
endif ()
endif ()
#
# Testing
#
if (CPPDUALS_TESTING)
enable_testing ()
include (CTest)
add_subdirectory (tests)
endif (CPPDUALS_TESTING)
#
# Documentation
#
find_program (DOXYGEN doxygen)
if (DOXYGEN)
configure_file (${PROJECT_SOURCE_DIR}/doc/Doxyfile.in ${PROJECT_BINARY_DIR}/doc/Doxyfile)
configure_file (${PROJECT_SOURCE_DIR}/doc/DoxygenLayout.xml ${PROJECT_BINARY_DIR}/doc/DoxygenLayout.xml COPYONLY)
configure_file (${PROJECT_SOURCE_DIR}/doc/header.html ${PROJECT_BINARY_DIR}/doc/header.html COPYONLY)
configure_file (${PROJECT_SOURCE_DIR}/doc/footer.html ${PROJECT_BINARY_DIR}/doc/footer.html COPYONLY)
configure_file (${PROJECT_SOURCE_DIR}/doc/favicon.ico ${PROJECT_BINARY_DIR}/doc/favicon.ico COPYONLY)
configure_file (${PROJECT_SOURCE_DIR}/doc/customdoxygen.css ${PROJECT_BINARY_DIR}/doc/customdoxygen.css)
add_custom_target (cppduals_docs
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/doc
COMMAND cmake -E remove_directory ${PROJECT_BINARY_DIR}/docs
COMMAND ${DOXYGEN} Doxyfile
)
else ()
add_custom_target (cppduals_docs
COMMAND echo "Please install doxygen and reconfigure to build the docs"
)
endif ()
#
# Installation
#
install (TARGETS cppduals_duals EXPORT cppduals_export)
install (EXPORT cppduals_export
FILE cppduals-config.cmake
NAMESPACE cppduals::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cppduals
)
install (
DIRECTORY ${PROJECT_SOURCE_DIR}/duals
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
PATTERN "*~" EXCLUDE
)
install (
DIRECTORY ${PROJECT_BINARY_DIR}/docs/ # Trailing slash triggers rename
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/cppduals
OPTIONAL
)
#
# etags
#
find_program (ETAGS etags)
if (ETAGS)
add_custom_target (cppduals_etags
COMMAND ${ETAGS} --language=c++ ${PROJECT_SOURCE_DIR}/duals/*
COMMAND ${ETAGS} --language=c++ --append ${PROJECT_SOURCE_DIR}/duals/arch/*/*
COMMAND ${ETAGS} --language=c++ --append `find ${PROJECT_BINARY_DIR}/thirdparty/eigenX/src/eigenX -type f`
)
endif (ETAGS)

373
src/include/cppduals/LICENSE.txt

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

354
src/include/cppduals/README.md

@ -0,0 +1,354 @@
cppduals
========
Header-only dual number library for C++11. The `dual<>` type can be
used for automatic (forward) differentiation. It can be used in
conjunction with Eigen to produced very fast vectorized computations
of real and complex matrix functions and their derivatives.
There is a small paper on cppduals here:
[![DOI](https://joss.theoj.org/papers/10.21105/joss.01487/status.svg)](https://doi.org/10.21105/joss.01487)
Documentation
=============
[Full documentation is here](https://tesch1.gitlab.io/cppduals/).
The dual number space is closely related to the complex number space,
and as such, the dual class `duals::dual<>` is similar to
`std::complex<>`.
When compiling with Eigen it is possible to disable the vectorization
templates by `#define CPPDUALS_DONT_VECTORIZE`. This may be useful if
your compiler is particularly good at optimizing Eigen expressions, I
have had mixed results, sometimes there are differences between the
compiler's best (GCC and Clang) and the vectorized code of 30% or
more, in either direction.
Examples
========
Here we calculate a function $`f(x)`$, with its derivative $`f'(x)`$,
calculated explicitly as `df()`, and calculated by using the dual
class (`1_e` returns the dual number $`0 + 1 \epsilon`$, it is
equivalent to `dual<double>(0,1)`):
```cpp
#include <duals/dual>
using namespace duals::literals;
template <class T> T f(T x) { return pow(x,pow(x,x)); }
template <class T> T df(T x) { return pow(x,-1. + x + pow(x,x)) * (1. + x*log(x) + x*pow(log(x),2.)); }
template <class T> T ddf(T x) { return (pow(x,pow(x,x)) * pow(pow(x,x - 1.) + pow(x,x)*log(x)*(log(x) + 1.), 2.) +
pow(x,pow(x,x)) * (pow(x,x - 1.) * log(x) +
pow(x,x - 1.) * (log(x) + 1.) +
pow(x,x - 1.) * ((x - 1.)/x + log(x)) +
pow(x,x) * log(x) * pow(log(x) + 1., 2.) )); }
int main()
{
std::cout << " f(2.) = " << f(2.) << "\n";
std::cout << " df(2.) = " << df(2.) << "\n";
std::cout << "ddf(2.) = " << ddf(2.) << "\n";
std::cout << " f(2+1_e) = " << f(2+1_e) << "\n";
std::cout << " f(2+1_e).dpart() = " << f(2+1_e).dpart() << "\n";
duals::hyperduald x(2+1_e,1+0_e);
std::cout << " f((2+1_e) + (1+0_e)_e).dpart().dpart() = " << f(x).dpart().dpart() << "\n";
}
```
Produces:
```
f(2.) = 16
df(2.) = 107.11
ddf(2.) = 958.755
f(2+1_e) = (16+107.11_e)
f(2+1_e).dpart() = 107.11
f((2+1_e) + (1+0_e)_e).dpart().dpart() = 958.755
```
Installation
============
Copy the [duals/](./duals/) directory (or just [dual](./duals/dual) )
somewhere your `#include`s can find it. Then just `#include
<duals/dual[_eigen]>` from your source.
Alternatively, `cppduals` supports building with CMake. If using CMake v3.14+,
the ``FetchContent`` pattern is straightforward and enables using CMake targets
to specify library dependencies:
```cmake
include(FetchContent)
# Have CMake download the library
set (CPPDUALS_TAG v0.4.1)
set (CPPDUALS_MD5 7efe49496b8d0e3d3ffbcd3c68f542f3)
FetchContent_Declare (cppduals
URL https://gitlab.com/tesch1/cppduals/-/archive/${CPPDUALS_TAG}/cppduals-${CPPDUALS_TAG}.tar.bz2
URL_HASH MD5=${CPPDUALS_MD5}
)
FetchContent_MakeAvailable (cppduals)
# Link to cppduals
target_link_libraries (your_target PRIVATE cppduals::duals)
```
Older versions of CMake can achieve a similar result using the ``ExternalProject``
family of commands and modifying the global preprocessor search path:
```cmake
include(ExternalProject)
# Have CMake download the library headers only
set (CPPDUALS_TAG v0.4.1)
set (CPPDUALS_MD5 7efe49496b8d0e3d3ffbcd3c68f542f3)
ExternalProject_Add (cppduals
URL https://gitlab.com/tesch1/cppduals/-/archive/${CPPDUALS_TAG}/cppduals-${CPPDUALS_TAG}.tar.bz2
URL_HASH MD5=${CPPDUALS_MD5}
CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" )
# Make include directory globally visible
ExternalProject_Get_Property (cppduals source_dir)
include_directories (${source_dir}/)
```
Alternatively, `cppduals` supports installation and discovery via the
`find_package` utility. First, download and install the library to a
location of your choosing:
```sh
CPPDUALS_PREFIX=<desired_install_location>
git clone https://gitlab.com/tesch1/cppduals.git && cd cppduals
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX="$CPPDUALS_PREFIX" ..
cmake --build . --target install
```
Then, in your project's `CMakeLists.txt`, find and link to the library in the
standard manner:
```cmake
find_package(cppduals REQUIRED)
target_link_libraries(your_target PRIVATE cppduals::cppduals)
```
If you installed `cppduals` to a location that is not on `find_package`'s
default search path, you can specify the location by setting the `cppduals_DIR`
environment variable when configuring your project:
```sh
cd your_build_dir
cppduals_DIR="${CPPDUALS_PREFIX}" cmake ..
```
Benchmarks
==========
The benchmark compares cppduals against a local BLAS implementation,
by default OpenBLAS (whose development package is required;
RedHat-flavor: `openblas-devel`, Debian-flavor: `openblas-dev`). If
you wish to build the benchmarks against a different installation of
BLAS, the following CMake variables can be set at configuration time:
- [BLA_VENDOR](https://cmake.org/cmake/help/latest/module/FindBLAS.html)
- BLAS_DIR
- LAPACK_DIR
For example, to build and run the tests shown below:
```sh
cmake -Bbuild-bench -H. -DCPPDUALS_BENCHMARK=ON -DBLAS_DIR=/opt/local -DLAPACK_DIR=/opt/local
cmake --build build-bench --target bench_gemm
./build-bench/tests/bench_gemm
```
The first performance goal of this project is to make the
`duals::dual<>` type at least as fast as `std::complex<>`. This is
considered to be an upper-bound for performance because complex math
operations are usually highly optimized for scientific computing and
have a similar algebraic structure. The second goal is to make the
compound type `std::complex<duals::dual<>>` as fast as possible for
use in calculation that require the derivative of complex functions
(ie comprising quantum-mechanical wave functions).
The first goal is measured by comparing the speed of matrix-matrix
operations (nominally matrix multiplication) on `duals::dual<>`-valued
Eigen matrices with highly optimtimized BLAS implementations of
equivalent operations on complex-valued matrices. This can be done by
running the [./tests/bench_gemm](./tests/bench_gemm.cpp) program. In
the *ideal* case, the results of the `B_MatMat<dual{f,d}>` type should
be nearly as fast, or faster than equivalently sized
`B_MatMat<complex{f,d}>`, and double-sized
`B_MatMatBLAS<{float,double}>` operations. This is very difficult to
achieve in reality, as the BLAS libraries typically use hand-tuned
assembly, where the Eigen libraries must strive to express the
calculation in a general form that the compiler can turn into optimal
code.
Comparing Eigen 3.3.7 and OpenBLAS 0.3.6 on an `Intel(R) Core(TM)
i7-7700 CPU @ 3.60GHz` is still sub-optimal, only achieving about half
the performance of the BLAS equivalent, and 90% of
`std::complex<float>`:
B_MatMat<dualf,dualf>/32 5433 ns 5427 ns
B_MatMat<dualf,dualf>/64 38478 ns 38433 ns
B_MatMat<dualf,dualf>/128 299450 ns 298981 ns
B_MatMat<dualf,dualf>/256 2365347 ns 2361566 ns
B_MatMat<dualf,dualf>/512 18888220 ns 18857342 ns
B_MatMat<dualf,dualf>/1024 151079955 ns 150856120 ns
B_MatMat<complexf,complexf>/32 4963 ns 4955 ns
B_MatMat<complexf,complexf>/64 36716 ns 36671 ns
B_MatMat<complexf,complexf>/128 280870 ns 280346 ns
B_MatMat<complexf,complexf>/256 2173791 ns 2170886 ns
B_MatMat<complexf,complexf>/512 17493222 ns 17459890 ns
B_MatMat<complexf,complexf>/1024 138498432 ns 138286283 ns
B_MatMatBLAS<complexf>/32 4877 ns 4870 ns
B_MatMatBLAS<complexf>/64 27722 ns 27691 ns
B_MatMatBLAS<complexf>/128 177084 ns 176756 ns
B_MatMatBLAS<complexf>/256 1268715 ns 1266445 ns
B_MatMatBLAS<complexf>/512 9772184 ns 9726621 ns
B_MatMatBLAS<complexf>/1024 75915016 ns 75432354 ns
The second benchmark of interest measures how well the nested
specializations `std::complex<duals::dual<>>` perform as matrix values
relative to using a BLAS library with an extended matrix to compute
the same value function. This comparison is also made with the
[./tests/bench_gemm](./tests/bench_gemm.cpp) program. The relevant
measures are `B_MatMat<cdual{f,d}>` and `B_MatMatBLAS<complex{f,d}>`
of twice the size.
On the same machine as above, using `std::complex<duals::dual<float>>`
(`cdualf`) shows a speed advantage over the BLAS approach, while using
only half the memory. However, notice that the advantage decreases as
the matrices get larger, which ideally should not happen:
B_MatMat<cdualf,cdualf>/16 2810 ns 2808 ns
B_MatMat<cdualf,cdualf>/32 19900 ns 19878 ns
B_MatMat<cdualf,cdualf>/64 151837 ns 151646 ns
B_MatMat<cdualf,cdualf>/128 1174699 ns 1172931 ns
B_MatMat<cdualf,cdualf>/256 9122903 ns 9110123 ns
B_MatMat<cdualf,cdualf>/512 72575352 ns 72467264 ns
B_MatMatBLAS<complexf>/32 4877 ns 4870 ns
B_MatMatBLAS<complexf>/64 27722 ns 27691 ns
B_MatMatBLAS<complexf>/128 177084 ns 176756 ns
B_MatMatBLAS<complexf>/256 1268715 ns 1266445 ns
B_MatMatBLAS<complexf>/512 9772184 ns 9726621 ns
B_MatMatBLAS<complexf>/1024 75915016 ns 75432354 ns
Contributions
=============
Questions, bug reports, bug fixes, and contributions are welcome.
Simply submit an [Issue](https://gitlab.com/tesch1/cppduals/issues)
or [Merge Request](https://gitlab.com/tesch1/cppduals/merge_requests).
Contributors
------------
- [Nestor Demeure](https://gitlab.com/nestordemeure)
- [Jeff](https://github.com/flying-tiger)
Compiler notes
==============
XCode 11 (Apple Clang 11) is known to work. Also various version of
g++. Clang 8.0 appears to have some trouble with compiling the
optimized templates for Eigen, as evidenced by its propensity to
segfault when compiling the cppduals test programs. Please submit
issues if you experience similar problems, with specifics of your
compiler and compilation flags.
License
=======
The primary header file `duals/dual` and testing and benchmarking code
is licensed under the following:
```
Part of the cppduals project.
https://tesch1.gitlab.io/cppduals
(c)2019 Michael Tesch. tesch1@gmail.com
See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
license information.
This Source Code Form is subject to the terms of the Mozilla
Public License v. 2.0. If a copy of the MPL was not distributed
with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
```
Eigen-derived
-------------
The support for Eigen vectorization, including `duals/dual_eigen` and
the architecture-specific vectorization files under `duals/arch` are
derived from the [Eigen
project](http://eigen.tuxfamily.org/index.php?title=Main_Page), and
thus licensed under [MPL-2](http://www.mozilla.org/MPL/2.0/FAQ.html) .
ChangeLog
=========
v0.4.1
======
- changed constexpr to FMT_CONSTEXPR in the dual<> and complex<>
formatters to work with more compilers / lang standards.
v0.4.0
======
- cleaned-up release with fixes from v0.3.2.
- improved docs
v0.3.3+
=======
- ignore these, will be, trying to cleanup release tarballs, next
stable will be v0.4.0
v0.3.2
======
- not actually tagged release
- fixed a bug in the `{fmt}` support, added docs for the same.
- added benchmarking for `{fmt}` vs iostreams.
v0.3.1
======
- forgot to bump the CMakeLists package version number in 0.3.0.
v0.3.0
======
- vastly improved cmake support, thanks to
[Jeff](https://gitlab.com/flying-tiger). The improvements required
changing some CMake target names.
- Added basic optional [libfmt](https://github.com/fmtlib/fmt) support for
duals::dual<> and std::complex<>, enabled with `#define`\ s
v0.2.0
======
- fixed build on VS2017
- save and restore signam and errno in {t,l}gamma
- fixes from Nestor D. for https://gitlab.com/tesch1/cppduals/issues/5 (spurious nan)
Todo
====
- Add multi-variate differentiation capability.
- Non-x86_64 (CUDA/AltiVec/HIP/NEON/...) vectorization.
- Higher-order derivatives.

2391
src/include/cppduals/doc/Doxyfile.in
File diff suppressed because it is too large
View File

195
src/include/cppduals/doc/DoxygenLayout.xml

@ -0,0 +1,195 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.8.14 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="user" url="https://gitlab.com/tesch1/cppduals" title="GitLab Repo"/>
<!-- tab type="pages" visible="yes" title="" intro=""/ -->
<tab type="modules" visible="yes" title="" intro=""/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

12
src/include/cppduals/doc/Greek_Epsilon_archaic.svg

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" width="42.519684" height="53.149605" id="svg2">
<defs id="defs4"/>
<g id="layer2" style="display:none">
<rect width="31.949493" height="34.973034" ry="0.21325016" x="5.0068707" y="9.2631512" id="rect3211" style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.07031591;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
<rect width="42.519684" height="53.149605" ry="0.32408288" x="-3.1811524e-06" y="-1.6357421e-06" id="rect2383" style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
</g>
<g id="layer3" style="display:inline">
<path d="M 11.632405,9.1085188 L 8.0202222,43.827366 L 12.558227,44.299504 L 13.502504,35.223494 L 31.250416,44.109226 L 32.657186,41.459326 L 13.835588,32.022025 L 14.68285,23.878481 L 32.430762,32.764213 L 33.837533,30.114312 L 15.015935,20.677012 L 15.821157,12.937537 L 33.330112,21.704152 L 34.736883,19.054251 L 16.154241,9.3902177 L 11.632405,9.1085188 z" id="rect2802" style="opacity:1;fill:#dcdccc;fill-opacity:1;fill-rule:nonzero;stroke:#dcdccc;stroke-width:0.11321644;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"/>
</g>
</svg>

2059
src/include/cppduals/doc/customdoxygen.css
File diff suppressed because it is too large
View File

BIN
src/include/cppduals/doc/favicon.ico

20
src/include/cppduals/doc/footer.html

@ -0,0 +1,20 @@
<!-- HTML footer for doxygen 1.8.14-->
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer">
<small>
$generatedby &#160;<a href="http://www.doxygen.org/index.html"> doxygen</a>
</small></address>
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

200
src/include/cppduals/doc/gitlab-release

@ -0,0 +1,200 @@
#!/usr/bin/env python3
# found on github, of all places, with an MIT license:
# MIT License
#
# Copyright (c) 2017 iNet Process
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import argparse
import os
import sys
from distutils.version import LooseVersion
from urllib.parse import urljoin, quote_plus
import requests
class GitlabReleaseError(RuntimeError):
pass
class GitlabRelease:
def __init__(self, debug=False):
self.env = {}
self.fetch_all_env()
self.api_project_url = self.get_api_project_url()
self.debug = debug
def fetch_env_var(self, name, msg):
if name not in self.env:
try:
self.env[name] = os.environ[name]
except KeyError:
raise GitlabReleaseError('Missing environment variable \'{}\': {}'.format(name, msg))
return self.env[name]
def is_gitlab_v9(self):
gl_version = self.fetch_env_var('CI_SERVER_VERSION', '')
return LooseVersion(gl_version) >= LooseVersion('9.0.0')
def get_tag(self):
tag_env = 'CI_BUILD_TAG'
if self.is_gitlab_v9():
tag_env = 'CI_COMMIT_TAG'
return self.fetch_env_var(tag_env, 'Releases can only be created on tag build.')
def fetch_all_env(self):
env = {
'CI_PROJECT_URL': '',
'CI_PROJECT_ID': '',
'GITLAB_ACCESS_TOKEN': "You must specifiy the private token linked to your GitLab account.\n"
'You probably need to add a GITLAB_ACCESS_TOKEN variable to your project.',
}
for var, msg in env.items():
self.fetch_env_var(var, msg)
def get_api_project_url(self):
api_version = 'v3'
if self.is_gitlab_v9():
api_version = 'v4'
return urljoin(self.env['CI_PROJECT_URL'],
'/api/{}/projects/{}'.format(api_version, self.env['CI_PROJECT_ID']))
def post_file(self, filename):
url = '/'.join((self.api_project_url, 'uploads'))
files = {'file': open(filename, 'rb')}
res = self.request('post', url, files=files)
return res.json()['markdown']
def fetch_links(self):
url = '/'.join((self.api_project_url, 'releases', self.get_tag(), 'assets/links'))
headers = {'Content-Type': 'application/json'}
res = self.request('get', url, headers=headers)
return res.json()
def set_links(self, links, update=False):
url = '/'.join((self.api_project_url, 'releases', self.get_tag(), 'assets/links'))
headers = {'Content-Type': 'application/json'}
method = 'put' if update else 'post'
res = self.request(method, url, headers=headers, json=links)
return res.json()
def set_release(self, message, update=False):
url = '/'.join((self.api_project_url, 'repository/tags', self.get_tag(), 'release'))
headers = {'Content-Type': 'application/json'}
body = {'description': message}
method = 'put' if update else 'post'
res = self.request(method, url, headers=headers, json=body)
return res.json()
def fetch_release(self):
url = '/'.join((self.api_project_url, 'repository/tags', self.get_tag()))
res = self.request('get', url)
return res.json()['release']
def request(self, method, url, **kwargs):
if 'headers' not in kwargs:
kwargs['headers'] = {}
kwargs['headers']['PRIVATE-TOKEN'] = self.env['GITLAB_ACCESS_TOKEN']
if self.debug:
print(url)
if 'body' in kwargs['headers']:
print(kwargs['headers']['body'])
res = requests.request(method, url, **kwargs)
res.raise_for_status()
if self.debug:
print(res.content)
return res
def create_release(self, message, files):
links = ['* ' + self.post_file(filename) for filename in files]
links.insert(0, message)
existing_release = self.fetch_release()
update = False
if existing_release is not None:
links = [existing_release['description'], '---'] + links
update = True
return self.set_release("\n\n".join(links), update)
if __name__ == '__main__':
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description='''
This program is intended to be used in a GitLab CI job in a Runner with Docker.
### 1. Configure your `.gitlab-ci.yml`
To make an automatic release you need to add something like this to the file
`.gitlab-ci.yml` in your project.
```yaml
stages:
- build
- publish
build:
stage: build
script:
- my_build_command
artifacts:
expire_in: '1 hour'
paths:
- compiled-$CI_BUILD_TAG.exe
- doc-$CI_BUILD_TAG.pdf
publish:
image: inetprocess/gitlab-release
stage: publish
only:
- tags
script:
- gitlab-release compiled-$CI_BUILD_TAG.exe doc-$CI_BUILD_TAG.pdf
```
### 2. Generate a personnal access token
Generate a new [Personal Access Token]
(https://docs.gitlab.com/ee/api/README.html#personal-access-tokens)
from your user profile.
### 3. Configure your project
Set a [secret variable](https://docs.gitlab.com/ce/ci/variables/#secret-variables)
in your project named `GITLAB_ACCESS_TOKEN` with the token you have generated in
the previous step.
'''
)
parser.add_argument('-m', '--message', default='',
help='Markdown message before the files list in the release note')
parser.add_argument('files', nargs='*',
help='Files to link in the release.')
parser.add_argument('-d', '--debug', action='store_true',
help='Print debug messages')
parser.add_argument('-l', '--links', action='store_true',
help='Print project links')
args = parser.parse_args()
#os.environ['CI_PROJECT_ID'] = 'tesch1%2Fcppduals'
#os.environ['CI_BUILD_TAG'] = 'v0.3.1'
#os.environ['CI_COMMIT_TAG'] = 'v0.3.1'
#os.environ['CI_PROJECT_URL'] = 'https://gitlab.com'
#os.environ['CI_SERVER_VERSION'] = '9.0.0'
#os.environ['GITLAB_ACCESS_TOKEN'] = ''
try:
release = GitlabRelease(args.debug)
#if args.links:
# print(release.fetch_links())
# sys.exit(0)
info = release.create_release(args.message, args.files)
print("Release: {tag_name} created.\n{description}".format_map(info))
except GitlabReleaseError as err:
print(err)
sys.exit(1)

57
src/include/cppduals/doc/header.html

@ -0,0 +1,57 @@
<!-- HTML header for doxygen 1.8.14-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="shortcut icon" href="$relpath^favicon.ico" type="image/x-icon" />
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" height="100" src="$relpath^$projectlogo"/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td style="padding-left: 0.5em;">
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

510
src/include/cppduals/duals/arch/AVX/ComplexDual.h

@ -0,0 +1,510 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2019 Michael Tesch <tesch1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CDUAL_AVX_H
#define EIGEN_CDUAL_AVX_H
namespace Eigen {
namespace internal {
#define vec8f_swizzle1(v,p,q,r,s) \
(_mm256_permute_ps(v, ((s)<<6|(r)<<4|(q)<<2|(p))))
#ifdef __AVX2__
#define vec4d_swizzle1(v,p,q,r,s) \
(_mm256_permute4x64_pd(v,(s)<<6|(r)<<4|(q)<<2|(p)))
#else
//#error "TODO"
#endif
//---------- float ----------
struct Packet2cdf
{
EIGEN_STRONG_INLINE Packet2cdf() {}
EIGEN_STRONG_INLINE explicit Packet2cdf(const __m256 & a) : v(a) {}
EIGEN_STRONG_INLINE explicit Packet2cdf(const Packet4df & a) : v(a.v) {}
//__m256 v;
Packet4df v;
};
// Use the packet_traits defined in AVX/PacketMath.h instead if we're going
// to leverage AVX instructions.
#if !defined(CPPDUALS_DONT_VECTORIZE_CDUAL)
template<> struct packet_traits<std::complex<duals::dual<float> > > : default_packet_traits
{
typedef Packet2cdf type;
typedef Packet1cdf half;
enum {
Vectorizable = 1,
AlignedOnScalar = 0,
size = 2,
HasHalfPacket = 1,
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0
};
};
#endif
template<> struct unpacket_traits<Packet2cdf> {
typedef std::complex<duals::dual<float> > type;
enum {size=2, alignment=Aligned32, masked_load_available=false, masked_store_available=false, vectorizable=true};
typedef Packet1cdf half;
};
template<> EIGEN_STRONG_INLINE Packet2cdf padd<Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{ return Packet2cdf(_mm256_add_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf psub<Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{ return Packet2cdf(_mm256_sub_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf pnegate(const Packet2cdf& a) { return Packet2cdf(pnegate(a.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf pconj(const Packet2cdf& a)
{
const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000,0x00000000,0x80000000,0x80000000,
0x00000000,0x00000000,0x80000000,0x80000000));
return Packet2cdf(_mm256_xor_ps(a.v.v,mask));
}
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<float> > pfirst<Packet2cdf>(const Packet2cdf& a)
{
EIGEN_ALIGN32 float res[8];
_mm256_store_ps(res, a.v.v);
return std::complex<duals::dual<float> >(duals::dual<float>(res[0],res[1]),
duals::dual<float>(res[2],res[3]));
}
template<> EIGEN_STRONG_INLINE Packet2cdf pmul<Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{
#ifdef __FMA__xx
const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000,0x00000000,0xffffffff,0xffffffff,
0x00000000,0x00000000,0xffffffff,0xffffffff));
Packet2cdf x(vec8f_swizzle1
(_mm256_addsub_ps(_mm256_fmadd_ps(vec8f_swizzle1(a.v.v, 0, 0, 0, 0),
vec8f_swizzle1(b.v.v, 0, 2, 1, 3),
_mm256_and_ps(mask,
_mm256_mul_ps(vec8f_swizzle1(a.v.v, 0, 0, 1, 1),
vec8f_swizzle1(b.v.v, 0, 0, 0, 2)))),
_mm256_fmadd_ps(vec8f_swizzle1(a.v.v, 2, 2, 2, 2),
vec8f_swizzle1(b.v.v, 2, 0, 3, 1),
_mm256_and_ps(mask,
_mm256_mul_ps(vec8f_swizzle1(a.v.v, 0, 0, 3, 3),
vec8f_swizzle1(b.v.v, 0, 0, 2, 0))))),
0,2,1,3));
return x;
#else
// help gcc
__m256 y0 = a.v.v;
__m256 y1 = _mm256_permute_ps(y0,0);
__m256 y2 = b.v.v;
__m256 y3 = _mm256_permute_ps(y2,216);
y1 = _mm256_mul_ps(y1,y3);
y3 = _mm256_permute_ps(y0,84);
__m256 y4 = _mm256_permute_ps(y2,132);
y3 = _mm256_mul_ps(y3,y4);
y4 = _mm256_setzero_ps();
y3 = _mm256_blend_ps(y4,y3,204);
y1 = _mm256_add_ps(y1,y3);
y3 = _mm256_permute_ps(y0,170);
__m256 y5 = _mm256_permute_ps(y2,114);
y3 = _mm256_mul_ps(y3,y5);
y0 = _mm256_movehdup_ps(y0);
y2 = _mm256_permute_ps(y2,36);
y0 = _mm256_mul_ps(y0,y2);
y0 = _mm256_blend_ps(y4,y0,204);
y0 = _mm256_add_ps(y3,y0);
y0 = _mm256_addsub_ps(y1,y0);
y0 = _mm256_permute_ps(y0,216);
return Packet2cdf(y0);
#endif
}
template<> EIGEN_STRONG_INLINE Packet2cdf pand <Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{ return Packet2cdf(_mm256_and_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf por <Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{ return Packet2cdf(_mm256_or_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf pxor <Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{ return Packet2cdf(_mm256_xor_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf pandnot<Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{ return Packet2cdf(_mm256_andnot_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet2cdf pload <Packet2cdf>(const std::complex<duals::dual<float> >* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet2cdf(pload<Packet8f>((const float*)from)); }
template<> EIGEN_STRONG_INLINE Packet2cdf ploadu<Packet2cdf>(const std::complex<duals::dual<float> >* from)
{
EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cdf(_mm256_loadu_ps((float*)from));
}
template<> EIGEN_STRONG_INLINE Packet2cdf pset1<Packet2cdf>(const std::complex<duals::dual<float> >& from)
{
/* here we really have to use unaligned loads :( */
const __m128 v = ploadu<Packet4f>((float *)&from);
return Packet2cdf(_mm256_insertf128_ps(_mm256_castps128_ps256(v),v,1));
//return Packet2cdf(_mm256_set_m128(v,v)); // missing on older GCCs
}
template<> EIGEN_STRONG_INLINE Packet2cdf ploaddup<Packet2cdf>(const std::complex<duals::dual<float> >* from)
{ return pset1<Packet2cdf>(*from); }
// FIXME force unaligned store, this is a temporary fix
template<> EIGEN_STRONG_INLINE void
pstore <std::complex<duals::dual<float> > >(std::complex<duals::dual<float> > * to, const Packet2cdf& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, Packet8f(from.v.v)); }
template<> EIGEN_STRONG_INLINE void
pstoreu<std::complex<duals::dual<float> > >(std::complex<duals::dual<float> > * to, const Packet2cdf& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, Packet8f(from.v.v)); }
//template<> EIGEN_STRONG_INLINE void
//prefetch<std::complex<duals::dual<float> > >(const std::complex<duals::dual<float> > * addr)
//{ _mm256_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
template<> EIGEN_STRONG_INLINE Packet2cdf preverse(const Packet2cdf& a)
{
const __m256 result = _mm256_permute2f128_ps(a.v.v, a.v.v, 1);
return Packet2cdf(result);
}
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<float> > predux<Packet2cdf>(const Packet2cdf& a)
{
return pfirst(Packet2cdf(_mm256_add_ps(a.v.v, _mm256_permute2f128_ps(a.v.v, a.v.v, 1))));
}
template<> EIGEN_STRONG_INLINE Packet2cdf preduxp<Packet2cdf>(const Packet2cdf* vecs)
{
return vecs[0];
}
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<float> > predux_mul<Packet2cdf>(const Packet2cdf& a)
{
return pfirst(pmul(a, preverse(a)));
}
#if 0
template<int Offset>
struct palign_impl<Offset,Packet2cdf>
{
static EIGEN_STRONG_INLINE void run(Packet2cdf& /*first*/, const Packet2cdf& /*second*/)
{
// FIXME is it sure we never have to align a Packet2cdf?
// Even though a std::complex<duals::dual<float> > has 32 bytes, it is not necessarily aligned on a 32 byte boundary...
}
};
#endif
template<> struct conj_helper<Packet2cdf, Packet2cdf, false,true>
{
EIGEN_STRONG_INLINE Packet2cdf pmadd(const Packet2cdf& x, const Packet2cdf& y, const Packet2cdf& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2cdf pmul(const Packet2cdf& a, const Packet2cdf& b) const
{
//#ifdef EIGEN_VECTORIZE_SSE3
return internal::pmul(a, pconj(b));
//#else
// TODO for AVX
//const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
//return Packet2cdf(_mm_add_pd(_mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v.v, 0, 0), b.v), mask),
// _mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
// vec2d_swizzle1(b.v, 1, 0))));
//#endif
}
};
template<> struct conj_helper<Packet2cdf, Packet2cdf, true,false>
{
EIGEN_STRONG_INLINE Packet2cdf pmadd(const Packet2cdf& x, const Packet2cdf& y, const Packet2cdf& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2cdf pmul(const Packet2cdf& a, const Packet2cdf& b) const
{
//#ifdef EIGEN_VECTORIZE_SSE3
return internal::pmul(pconj(a), b);
//#else
//const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
//return Packet2cdf(_mm_add_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v),
// _mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
// vec2d_swizzle1(b.v, 1, 0)), mask)));
//#endif
}
};
template<> struct conj_helper<Packet2cdf, Packet2cdf, true,true>
{
EIGEN_STRONG_INLINE Packet2cdf pmadd(const Packet2cdf& x, const Packet2cdf& y, const Packet2cdf& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2cdf pmul(const Packet2cdf& a, const Packet2cdf& b) const
{
//#ifdef EIGEN_VECTORIZE_SSE3
return pconj(internal::pmul(a, b));
//#else
//const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
//return Packet2cdf(_mm_sub_pd(_mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v), mask),
// _mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
// vec2d_swizzle1(b.v, 1, 0))));
//#endif
}
};
//TODO
EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cdf,Packet4df)
template<> EIGEN_STRONG_INLINE Packet2cdf pdiv<Packet2cdf>(const Packet2cdf& a, const Packet2cdf& b)
{
Packet2cdf res = conj_helper<Packet2cdf,Packet2cdf,false,true>().pmul(a,b);
Packet4df s = pmul(b.v, b.v);
return Packet2cdf(pdiv(res.v,
padd(s, Packet4df(_mm256_castpd_ps(_mm256_shuffle_pd(_mm256_castps_pd(s.v),
_mm256_castps_pd(s.v), 0x5))))));
}
EIGEN_STRONG_INLINE Packet2cdf pcplxflip/* <Packet2cdf> */(const Packet2cdf& x)
{
return Packet2cdf(vec8f_swizzle1(x.v.v, 2, 3, 0, 1));
}
EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet2cdf,2> & kernel)
{
__m256d tmp = _mm256_permute2f128_pd(_mm256_castps_pd(kernel.packet[0].v.v),
_mm256_castps_pd(kernel.packet[1].v.v), 0+(2<<4));
kernel.packet[1].v.v = _mm256_castpd_ps(_mm256_permute2f128_pd(_mm256_castps_pd(kernel.packet[0].v.v),
_mm256_castps_pd(kernel.packet[1].v.v), 1+(3<<4)));
kernel.packet[0].v.v = _mm256_castpd_ps(tmp);
}
//---------- double ----------
#ifdef __AVX2__
struct Packet1cdd
{
EIGEN_STRONG_INLINE Packet1cdd() {}
EIGEN_STRONG_INLINE explicit Packet1cdd(const __m256d & a) : v(a) {}
EIGEN_STRONG_INLINE explicit Packet1cdd(const Packet2dd & a) : v(a) {}
//__m256d v;
Packet2dd v;
};
#if !defined(CPPDUALS_DONT_VECTORIZE_CDUAL)
template<> struct packet_traits<std::complex<duals::dual<double> > > : default_packet_traits
{
typedef Packet1cdd type;
typedef Packet1cdd half;
enum {
Vectorizable = 1,
AlignedOnScalar = 0,
size = 1,
HasHalfPacket = 0,
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0
};
};
#endif
template<> struct unpacket_traits<Packet1cdd> {
typedef std::complex<duals::dual<double> > type;
enum {size=1, alignment=Aligned32, masked_load_available=false, masked_store_available=false, vectorizable=true};
typedef Packet1cdd half;
};
template<> EIGEN_STRONG_INLINE Packet1cdd padd<Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{ return Packet1cdd(_mm256_add_pd(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd psub<Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{ return Packet1cdd(_mm256_sub_pd(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd pnegate(const Packet1cdd& a) { return Packet1cdd(pnegate(a.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd pconj(const Packet1cdd& a)
{
const __m256d mask = _mm256_castsi256_pd(_mm256_set_epi32(0x80000000,0x0,0x80000000,0x0,0x0,0x0,0x0,0x0));
return Packet1cdd(_mm256_xor_pd(a.v.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet1cdd pmul<Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{
#ifndef __AVX2__
// TODO
#error "no avx2, really?"
#endif
#ifdef __FMA__
const __m256d mask = _mm256_castsi256_pd(_mm256_setr_epi32(0x0,0x0,0x0,0x0,
0xffffffff,0xffffffff,0xffffffff,0xffffffff));
return Packet1cdd(vec4d_swizzle1
(_mm256_addsub_pd(_mm256_fmadd_pd(_mm256_broadcastsd_pd(_mm256_castpd256_pd128(a.v.v)),
vec4d_swizzle1(b.v.v, 0, 2, 1, 3),
_mm256_and_pd(mask,
_mm256_mul_pd(vec4d_swizzle1(a.v.v, 0, 0, 1, 1),
vec4d_swizzle1(b.v.v, 0, 0, 0, 2)))),
_mm256_fmadd_pd(vec4d_swizzle1(a.v.v, 2, 2, 2, 2),
vec4d_swizzle1(b.v.v, 2, 0, 3, 1),
_mm256_and_pd(mask,
_mm256_mul_pd(vec4d_swizzle1(a.v.v, 0, 0, 3, 3),
vec4d_swizzle1(b.v.v, 0, 0, 2, 0))))),
0,2,1,3));
#else
const __m256d mask = _mm256_castsi256_pd(_mm256_setr_epi32(0x0,0x0,0x0,0x0,
0xffffffff,0xffffffff,0xffffffff,0xffffffff));
return Packet1cdd(vec4d_swizzle1
(_mm256_addsub_pd(_mm256_add_pd(_mm256_mul_pd(_mm256_broadcastsd_pd(_mm256_castpd256_pd128(a.v.v)),
vec4d_swizzle1(b.v.v, 0, 2, 1, 3)),
_mm256_and_pd(mask,
_mm256_mul_pd(vec4d_swizzle1(a.v.v, 0, 0, 1, 1),
vec4d_swizzle1(b.v.v, 0, 0, 0, 2)))),
_mm256_add_pd(_mm256_mul_pd(vec4d_swizzle1(a.v.v, 2, 2, 2, 2),
vec4d_swizzle1(b.v.v, 2, 0, 3, 1)),
_mm256_and_pd(mask,
_mm256_mul_pd(vec4d_swizzle1(a.v.v, 0, 0, 3, 3),
vec4d_swizzle1(b.v.v, 0, 0, 2, 0))))),
0,2,1,3));
#endif
}
template<> EIGEN_STRONG_INLINE Packet1cdd pand <Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{ return Packet1cdd(_mm256_and_pd(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd por <Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{ return Packet1cdd(_mm256_or_pd(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd pxor <Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{ return Packet1cdd(_mm256_xor_pd(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd pandnot<Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{ return Packet1cdd(_mm256_andnot_pd(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdd pload <Packet1cdd>(const std::complex<duals::dual<double> >* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet1cdd(ploadu<Packet4d>((const double*)from)); }
template<> EIGEN_STRONG_INLINE Packet1cdd ploadu<Packet1cdd>(const std::complex<duals::dual<double> >* from)
{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cdd(ploadu<Packet4d>((const double*)from)); }
template<> EIGEN_STRONG_INLINE Packet1cdd pset1<Packet1cdd>(const std::complex<duals::dual<double> >& from)
{ /* here we really have to use unaligned loads :( */ return ploadu<Packet1cdd>(&from); }
template<> EIGEN_STRONG_INLINE Packet1cdd ploaddup<Packet1cdd>(const std::complex<duals::dual<double> >* from)
{ return pset1<Packet1cdd>(*from); }
// FIXME force unaligned store, this is a temporary fix
template<> EIGEN_STRONG_INLINE void
pstore <std::complex<duals::dual<double> > >(std::complex<duals::dual<double> > * to, const Packet1cdd& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstoreu((double*)to, from.v.v); }
template<> EIGEN_STRONG_INLINE void
pstoreu<std::complex<duals::dual<double> > >(std::complex<duals::dual<double> > * to, const Packet1cdd& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v.v); }
template<> EIGEN_STRONG_INLINE void
prefetch<std::complex<duals::dual<double> > >(const std::complex<duals::dual<double> > * addr)
{ _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<double> > pfirst<Packet1cdd>(const Packet1cdd& a)
{
EIGEN_ALIGN16 double res[4];
_mm256_store_pd(res, a.v.v);
return std::complex<duals::dual<double> >(duals::dual<double>(res[0],res[1]),
duals::dual<double>(res[2],res[3]));
}
template<> EIGEN_STRONG_INLINE Packet1cdd preverse(const Packet1cdd& a) { return a; }
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<double> > predux<Packet1cdd>(const Packet1cdd& a)
{
return pfirst(a);
}
template<> EIGEN_STRONG_INLINE Packet1cdd preduxp<Packet1cdd>(const Packet1cdd* vecs)
{
return vecs[0];
}
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<double> > predux_mul<Packet1cdd>(const Packet1cdd& a)
{
return pfirst(a);
}
template<int Offset>
struct palign_impl<Offset,Packet1cdd>
{
static EIGEN_STRONG_INLINE void run(Packet1cdd& /*first*/, const Packet1cdd& /*second*/)
{
// FIXME is it sure we never have to align a Packet1cdd?
// Even though a std::complex<duals::dual<double> > has 16 bytes, it is not necessarily aligned on a 16 bytes boundary...
}
};
template<> struct conj_helper<Packet1cdd, Packet1cdd, false,true>
{
EIGEN_STRONG_INLINE Packet1cdd pmadd(const Packet1cdd& x, const Packet1cdd& y, const Packet1cdd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1cdd pmul(const Packet1cdd& a, const Packet1cdd& b) const
{
return internal::pmul(a, pconj(b));
}
};
template<> struct conj_helper<Packet1cdd, Packet1cdd, true,false>
{
EIGEN_STRONG_INLINE Packet1cdd pmadd(const Packet1cdd& x, const Packet1cdd& y, const Packet1cdd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1cdd pmul(const Packet1cdd& a, const Packet1cdd& b) const
{
return internal::pmul(pconj(a), b);
}
};
template<> struct conj_helper<Packet1cdd, Packet1cdd, true,true>
{
EIGEN_STRONG_INLINE Packet1cdd pmadd(const Packet1cdd& x, const Packet1cdd& y, const Packet1cdd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1cdd pmul(const Packet1cdd& a, const Packet1cdd& b) const
{
return pconj(internal::pmul(a, b));
}
};
EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cdd,Packet2dd)
template<> EIGEN_STRONG_INLINE Packet1cdd pdiv<Packet1cdd>(const Packet1cdd& a, const Packet1cdd& b)
{
//Packet2cd num = pmul(a, pconj(b));
//__m256d tmp = _mm256_mul_pd(b.v, b.v);
//__m256d denom = _mm256_hadd_pd(tmp, tmp);
//return Packet2cd(_mm256_div_pd(num.v, denom));
Packet1cdd num = conj_helper<Packet1cdd,Packet1cdd,false,true>().pmul(a,b);
Packet2dd tmp = pmul(b.v, b.v);
Packet2dd denom ( _mm256_add_pd(tmp.v,
_mm256_permute2f128_pd(tmp.v,tmp.v, 1)));
return Packet1cdd(pdiv(num.v, denom));
}
EIGEN_STRONG_INLINE Packet1cdd pcplxflip/* <Packet1cdd> */(const Packet1cdd& x)
{
return Packet1cdd(_mm256_permute2f128_pd(x.v.v,x.v.v, 1));
}
#else
#warning "AVX2 disabled: not vectorizing std::complex<dual<double>>"
#endif
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_CDUAL_AVX_H

548
src/include/cppduals/duals/arch/AVX/Dual.h

@ -0,0 +1,548 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com)
// Copyright (C) 2019 Michael Tesch <tesch1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_DUAL_AVX_H
#define EIGEN_DUAL_AVX_H
namespace Eigen {
namespace internal {
//---------- float ----------
struct Packet4df
{
EIGEN_STRONG_INLINE Packet4df() {}
EIGEN_STRONG_INLINE explicit Packet4df(const __m256& a) : v(a) {}
__m256 v;
};
template<> struct packet_traits<duals::dual<float> > : default_packet_traits
{
typedef Packet4df type;
typedef Packet2df half;
enum {
Vectorizable = 1,
AlignedOnScalar = 1,
size = 4,
HasHalfPacket = 1,
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0
};
};
template<> struct unpacket_traits<Packet4df> {
typedef duals::dual<float> type;
enum {size=4, alignment=Aligned32, masked_load_available=false, masked_store_available=false, vectorizable=true};
typedef Packet2df half;
};
//template<> EIGEN_STRONG_INLINE Packet4df pzero(const Packet4df& /*a*/) { return Packet4df(_mm256_setzero_ps()); }
template<> EIGEN_STRONG_INLINE Packet4df padd<Packet4df>(const Packet4df& a, const Packet4df& b)
{ return Packet4df(_mm256_add_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet4df psub<Packet4df>(const Packet4df& a, const Packet4df& b)
{ return Packet4df(_mm256_sub_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet4df pnegate(const Packet4df& a)
{
return Packet4df(pnegate(a.v));
}
template<> EIGEN_STRONG_INLINE Packet4df pdconj(const Packet4df& a)
{
const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000,
0x00000000,0x80000000,0x00000000,0x80000000));
return Packet4df(_mm256_xor_ps(a.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet4df pconj(const Packet4df& a) { return a; }
template<> EIGEN_STRONG_INLINE Packet4df pmul<Packet4df>(const Packet4df& a, const Packet4df& b)
{
#ifdef xx__FMA__
__m256 result = _mm256_fmadd_ps(_mm256_moveldup_ps(a.v),
b.v,
_mm256_blend_ps(_mm256_setzero_ps(),
_mm256_mul_ps(_mm256_moveldup_ps(b.v), a.v), 0xaa));
return Packet4df(result);
#else
__m256 result = _mm256_add_ps(_mm256_mul_ps(_mm256_moveldup_ps(a.v), b.v),
_mm256_blend_ps(_mm256_setzero_ps(),
_mm256_mul_ps(_mm256_moveldup_ps(b.v), a.v), 0xaa));
#endif
return Packet4df(result);
}
template<> EIGEN_STRONG_INLINE Packet4df pand <Packet4df>(const Packet4df& a, const Packet4df& b)
{ return Packet4df(_mm256_and_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet4df por <Packet4df>(const Packet4df& a, const Packet4df& b)
{ return Packet4df(_mm256_or_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet4df pxor <Packet4df>(const Packet4df& a, const Packet4df& b)
{ return Packet4df(_mm256_xor_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet4df pandnot<Packet4df>(const Packet4df& a, const Packet4df& b)
{ return Packet4df(_mm256_andnot_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet4df pload1<Packet4df>(const duals::dual<float>* from)
{
return Packet4df(_mm256_castpd_ps(_mm256_broadcast_sd((const double*)(const void*)from)));
}
template<> EIGEN_STRONG_INLINE Packet4df pload <Packet4df>(const duals::dual<float>* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet4df(pload<Packet8f>(&numext::real_ref(*from))); }
template<> EIGEN_STRONG_INLINE Packet4df ploadu<Packet4df>(const duals::dual<float>* from)
{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet4df(ploadu<Packet8f>(&numext::real_ref(*from))); }
template<> EIGEN_STRONG_INLINE Packet4df pset1<Packet4df>(const duals::dual<float>& from)
{
return Packet4df(_mm256_castpd_ps(_mm256_broadcast_sd((const double*)(const void*)&from)));
}
template<> EIGEN_STRONG_INLINE Packet4df ploaddup<Packet4df>(const duals::dual<float>* from)
{
// FIXME The following might be optimized using _mm256_movedup_pd
Packet2df a = ploaddup<Packet2df>(from);
Packet2df b = ploaddup<Packet2df>(from+1);
return Packet4df(_mm256_insertf128_ps(_mm256_castps128_ps256(a.v), b.v, 1));
}
template<> EIGEN_STRONG_INLINE void pstore <duals::dual<float> >(duals::dual<float>* to, const Packet4df& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstore(&numext::real_ref(*to), from.v); }
template<> EIGEN_STRONG_INLINE void pstoreu<duals::dual<float> >(duals::dual<float>* to, const Packet4df& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&numext::real_ref(*to), from.v); }
template<> EIGEN_DEVICE_FUNC inline Packet4df pgather<duals::dual<float>, Packet4df>(const duals::dual<float>* from,
Index stride)
{
return Packet4df(_mm256_set_ps(duals::dpart(from[3*stride]), duals::rpart(from[3*stride]),
duals::dpart(from[2*stride]), duals::rpart(from[2*stride]),
duals::dpart(from[1*stride]), duals::rpart(from[1*stride]),
duals::dpart(from[0*stride]), duals::rpart(from[0*stride])));
}
template<> EIGEN_DEVICE_FUNC inline void pscatter<duals::dual<float>, Packet4df>(duals::dual<float>* to,
const Packet4df& from, Index stride)
{
__m128 low = _mm256_extractf128_ps(from.v, 0);
to[stride*0] = duals::dual<float>(_mm_cvtss_f32(_mm_shuffle_ps(low, low, 0)),
_mm_cvtss_f32(_mm_shuffle_ps(low, low, 1)));
to[stride*1] = duals::dual<float>(_mm_cvtss_f32(_mm_shuffle_ps(low, low, 2)),
_mm_cvtss_f32(_mm_shuffle_ps(low, low, 3)));
__m128 high = _mm256_extractf128_ps(from.v, 1);
to[stride*2] = duals::dual<float>(_mm_cvtss_f32(_mm_shuffle_ps(high, high, 0)),
_mm_cvtss_f32(_mm_shuffle_ps(high, high, 1)));
to[stride*3] = duals::dual<float>(_mm_cvtss_f32(_mm_shuffle_ps(high, high, 2)),
_mm_cvtss_f32(_mm_shuffle_ps(high, high, 3)));
}
template<> EIGEN_STRONG_INLINE duals::dual<float> pfirst<Packet4df>(const Packet4df& a)
{
return pfirst(Packet2df(_mm256_castps256_ps128(a.v)));
}
template<> EIGEN_STRONG_INLINE Packet4df preverse(const Packet4df& a) {
__m128 low = _mm256_extractf128_ps(a.v, 0);
__m128 high = _mm256_extractf128_ps(a.v, 1);
__m128d lowd = _mm_castps_pd(low);
__m128d highd = _mm_castps_pd(high);
low = _mm_castpd_ps(_mm_shuffle_pd(lowd,lowd,0x1));
high = _mm_castpd_ps(_mm_shuffle_pd(highd,highd,0x1));
__m256 result = _mm256_setzero_ps();
result = _mm256_insertf128_ps(result, low, 1);
result = _mm256_insertf128_ps(result, high, 0);
return Packet4df(result);
}
template<> EIGEN_STRONG_INLINE duals::dual<float> predux<Packet4df>(const Packet4df& a)
{
return predux(padd(Packet2df(_mm256_extractf128_ps(a.v,0)),
Packet2df(_mm256_extractf128_ps(a.v,1))));
}
template<> EIGEN_STRONG_INLINE Packet4df preduxp<Packet4df>(const Packet4df* vecs)
{
Packet8f t0 = _mm256_shuffle_ps(vecs[0].v, vecs[0].v, _MM_SHUFFLE(3, 1, 2 ,0));
Packet8f t1 = _mm256_shuffle_ps(vecs[1].v, vecs[1].v, _MM_SHUFFLE(3, 1, 2 ,0));
t0 = _mm256_hadd_ps(t0,t1);
Packet8f t2 = _mm256_shuffle_ps(vecs[2].v, vecs[2].v, _MM_SHUFFLE(3, 1, 2 ,0));
Packet8f t3 = _mm256_shuffle_ps(vecs[3].v, vecs[3].v, _MM_SHUFFLE(3, 1, 2 ,0));
t2 = _mm256_hadd_ps(t2,t3);
t1 = _mm256_permute2f128_ps(t0,t2, 0 + (2<<4));
t3 = _mm256_permute2f128_ps(t0,t2, 1 + (3<<4));
return Packet4df(_mm256_add_ps(t1,t3));
}
template<> EIGEN_STRONG_INLINE duals::dual<float> predux_mul<Packet4df>(const Packet4df& a)
{
return predux_mul(pmul(Packet2df(_mm256_extractf128_ps(a.v, 0)),
Packet2df(_mm256_extractf128_ps(a.v, 1))));
}
template<int Offset>
struct palign_impl<Offset,Packet4df>
{
static EIGEN_STRONG_INLINE void run(Packet4df& first, const Packet4df& second)
{
if (Offset==0) return;
palign_impl<Offset*2,Packet8f>::run(first.v, second.v);
}
};
#if 0 // TODO
template<> struct dconj_helper<Packet4df, Packet4df, false,true>
{
EIGEN_STRONG_INLINE Packet4df pmadd(const Packet4df& x, const Packet4df& y, const Packet4df& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet4df pmul(const Packet4df& a, const Packet4df& b) const
{ return internal::pmul(a, pdconj(b)); }
};
template<> struct dconj_helper<Packet4df, Packet4df, true,false>
{
EIGEN_STRONG_INLINE Packet4df pmadd(const Packet4df& x, const Packet4df& y, const Packet4df& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet4df pmul(const Packet4df& a, const Packet4df& b) const
{ return internal::pmul(pdconj(a), b); }
};
template<> struct dconj_helper<Packet4df, Packet4df, true,true>
{
EIGEN_STRONG_INLINE Packet4df pmadd(const Packet4df& x, const Packet4df& y, const Packet4df& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet4df pmul(const Packet4df& a, const Packet4df& b) const
{ return pdconj(internal::pmul(a, b)); }
};
EIGEN_MAKE_DCONJ_HELPER_DUAL_REAL(Packet4df,Packet8f)
#endif
template<> EIGEN_STRONG_INLINE Packet4df pdiv<Packet4df>(const Packet4df& a, const Packet4df& b)
{
#if 0
// approxer, but faster?
const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0x00000000,0xffffffff,0x00000000,0xffffffff,
0x00000000,0xffffffff,0x00000000,0xffffffff));
__m256 xr = _mm256_moveldup_ps(b.v);
__m256 num = _mm256_sub_ps(_mm256_mul_ps(a.v, xr),
_mm256_and_ps(mask,
_mm256_mul_ps(b.v, _mm256_moveldup_ps(a.v))));
return Packet4df(_mm256_div_ps(num,
_mm256_mul_ps(xr,xr)));
#else
const __m256 mask = _mm256_castsi256_ps(_mm256_setr_epi32(0xffffffff,0x00000000,0xffffffff,0x00000000,
0xffffffff,0x00000000,0xffffffff,0x00000000));
__m256 xr = _mm256_moveldup_ps(b.v);
__m256 r = _mm256_div_ps(_mm256_add_ps(_mm256_and_ps(mask, a.v),
_mm256_andnot_ps(mask,
_mm256_sub_ps(_mm256_mul_ps(a.v, xr),
_mm256_mul_ps(b.v, _mm256_moveldup_ps(a.v))))),
_mm256_add_ps(_mm256_and_ps(mask, b.v),
_mm256_andnot_ps(mask,
_mm256_mul_ps(xr,xr))));
return Packet4df(r);
#endif
}
//---------- double ----------
struct Packet2dd
{
EIGEN_STRONG_INLINE Packet2dd() {}
EIGEN_STRONG_INLINE explicit Packet2dd(const __m256d& a) : v(a) {}
__m256d v;
};
template<> struct packet_traits<duals::dual<double> > : default_packet_traits
{
typedef Packet2dd type;
#if EIGEN_VERSION_AT_LEAST(3, 3, 8)
// sometime after 3.3.7 gebp_traits cant deal with this
#define TWODD_NOHALF
#endif
#ifdef TWODD_NOHALF
typedef Packet2dd half;
#else
typedef Packet1dd half;
#endif
enum {
Vectorizable = 1,
AlignedOnScalar = 0,
size = 2,
#ifdef TWODD_NOHALF
HasHalfPacket = 0,
#else
HasHalfPacket = 1,
#endif
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0
};
};
template<> struct unpacket_traits<Packet2dd> {
typedef duals::dual<double> type;
enum {size=2, alignment=Aligned32, masked_load_available=false, masked_store_available=false, vectorizable=true};
#ifdef TWODD_NOHALF
typedef Packet2dd half;
#else
typedef Packet1dd half;
#endif
};
template<> EIGEN_STRONG_INLINE Packet2dd padd<Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{ return Packet2dd(_mm256_add_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd psub<Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{ return Packet2dd(_mm256_sub_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd pnegate(const Packet2dd& a) { return Packet2dd(pnegate(a.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd pdconj(const Packet2dd& a)
{
const __m256d mask = _mm256_castsi256_pd(_mm256_set_epi32(0x80000000,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0));
return Packet2dd(_mm256_xor_pd(a.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet2dd pconj(const Packet2dd& a) { return a; }
template<> EIGEN_STRONG_INLINE Packet2dd pmul<Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{
#if 0
const __m256d mask = _mm256_castsi256_pd(_mm256_set_epi32(0xffffffff,0xffffffff,0x0,0x0,
0xffffffff,0xffffffff,0x0,0x0));
return Packet2dd(_mm256_add_pd(_mm256_and_pd(mask,
_mm256_mul_pd(a.v, _mm256_shuffle_pd(b.v,b.v,0x0))),
_mm256_mul_pd(b.v, _mm256_shuffle_pd(a.v,a.v,0x0))));
#else
#ifdef __FMA__ // not sure if this is actually faster.
return Packet2dd(_mm256_fmadd_pd(b.v,
_mm256_movedup_pd(a.v),
_mm256_blend_pd(_mm256_setzero_pd(),
_mm256_mul_pd(a.v, _mm256_movedup_pd(b.v)),
0xa)));
#else
return Packet2dd(_mm256_add_pd(_mm256_mul_pd(b.v,_mm256_movedup_pd(a.v)),
_mm256_blend_pd(_mm256_setzero_pd(),
_mm256_mul_pd(a.v, _mm256_movedup_pd(b.v)),
0xa)));
#endif
#endif
}
template<> EIGEN_STRONG_INLINE Packet2dd pand <Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{ return Packet2dd(_mm256_and_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd por <Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{ return Packet2dd(_mm256_or_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd pxor <Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{ return Packet2dd(_mm256_xor_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd pandnot<Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{ return Packet2dd(_mm256_andnot_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2dd pload <Packet2dd>(const duals::dual<double>* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet2dd(pload<Packet4d>((const double*)from)); }
template<> EIGEN_STRONG_INLINE Packet2dd ploadu<Packet2dd>(const duals::dual<double>* from)
{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet2dd(ploadu<Packet4d>((const double*)from)); }
template<> EIGEN_STRONG_INLINE Packet2dd pset1<Packet2dd>(const duals::dual<double>& from)
{
// in case casting to a __m128d* is really not safe, then we can still fallback to this version: (much slower though)
// return Packet2dd(_mm256_loadu2_m128d((const double*)&from,(const double*)&from));
return Packet2dd(_mm256_broadcast_pd((const __m128d*)(const void*)&from));
}
template<> EIGEN_STRONG_INLINE Packet2dd ploaddup<Packet2dd>(const duals::dual<double>* from)
{ return pset1<Packet2dd>(*from); }
template<> EIGEN_STRONG_INLINE void pstore <duals::dual<double> >(duals::dual<double> * to, const Packet2dd& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, from.v); }
template<> EIGEN_STRONG_INLINE void pstoreu<duals::dual<double> >(duals::dual<double> * to, const Packet2dd& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, from.v); }
template<> EIGEN_DEVICE_FUNC inline Packet2dd pgather<duals::dual<double>, Packet2dd>(const duals::dual<double>* from,
Index stride)
{
return Packet2dd(_mm256_set_pd(duals::dpart(from[1*stride]), duals::rpart(from[1*stride]),
duals::dpart(from[0*stride]), duals::rpart(from[0*stride])));
}
template<> EIGEN_DEVICE_FUNC inline void pscatter<duals::dual<double>, Packet2dd>(duals::dual<double>* to,
const Packet2dd& from, Index stride)
{
__m128d low = _mm256_extractf128_pd(from.v, 0);
to[stride*0] = duals::dual<double>(_mm_cvtsd_f64(low), _mm_cvtsd_f64(_mm_shuffle_pd(low, low, 1)));
__m128d high = _mm256_extractf128_pd(from.v, 1);
to[stride*1] = duals::dual<double>(_mm_cvtsd_f64(high), _mm_cvtsd_f64(_mm_shuffle_pd(high, high, 1)));
}
template<> EIGEN_STRONG_INLINE duals::dual<double> pfirst<Packet2dd>(const Packet2dd& a)
{
__m128d low = _mm256_extractf128_pd(a.v, 0);
EIGEN_ALIGN16 double res[2];
_mm_store_pd(res, low);
return duals::dual<double>(res[0],res[1]);
}
template<> EIGEN_STRONG_INLINE Packet2dd preverse(const Packet2dd& a) {
__m256d result = _mm256_permute2f128_pd(a.v, a.v, 1);
return Packet2dd(result);
}
template<> EIGEN_STRONG_INLINE duals::dual<double> predux<Packet2dd>(const Packet2dd& a)
{
return predux(padd(Packet1dd(_mm256_extractf128_pd(a.v,0)),
Packet1dd(_mm256_extractf128_pd(a.v,1))));
}
template<> EIGEN_STRONG_INLINE Packet2dd preduxp<Packet2dd>(const Packet2dd* vecs)
{
Packet4d t0 = _mm256_permute2f128_pd(vecs[0].v,vecs[1].v, 0 + (2<<4));
Packet4d t1 = _mm256_permute2f128_pd(vecs[0].v,vecs[1].v, 1 + (3<<4));
return Packet2dd(_mm256_add_pd(t0,t1));
}
template<> EIGEN_STRONG_INLINE duals::dual<double> predux_mul<Packet2dd>(const Packet2dd& a)
{
return pfirst(pmul(Packet1dd(_mm256_extractf128_pd(a.v,0)),
Packet1dd(_mm256_extractf128_pd(a.v,1))));
}
template<int Offset>
struct palign_impl<Offset,Packet2dd>
{
static EIGEN_STRONG_INLINE void run(Packet2dd& first, const Packet2dd& second)
{
if (Offset==0) return;
palign_impl<Offset*2,Packet4d>::run(first.v, second.v);
}
};
#if 0 // TODO
template<> struct dconj_helper<Packet2dd, Packet2dd, false,true>
{
EIGEN_STRONG_INLINE Packet2dd pmadd(const Packet2dd& x, const Packet2dd& y, const Packet2dd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2dd pmul(const Packet2dd& a, const Packet2dd& b) const
{ return internal::pmul(a, pdconj(b)); }
};
template<> struct dconj_helper<Packet2dd, Packet2dd, true,false>
{
EIGEN_STRONG_INLINE Packet2dd pmadd(const Packet2dd& x, const Packet2dd& y, const Packet2dd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2dd pmul(const Packet2dd& a, const Packet2dd& b) const
{ return internal::pmul(pdconj(a), b); }
};
template<> struct dconj_helper<Packet2dd, Packet2dd, true,true>
{
EIGEN_STRONG_INLINE Packet2dd pmadd(const Packet2dd& x, const Packet2dd& y, const Packet2dd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2dd pmul(const Packet2dd& a, const Packet2dd& b) const
{ return pdconj(internal::pmul(a, b)); }
};
EIGEN_MAKE_DCONJ_HELPER_DUAL_REAL(Packet2dd,Packet4d)
#endif
template<> EIGEN_STRONG_INLINE Packet2dd pdiv<Packet2dd>(const Packet2dd& a, const Packet2dd& b)
{
#if 1
// help gcc to not use 12 registers :P
__m256d y1 = _mm256_setzero_pd();
__m256d y2 = _mm256_blend_pd(a.v, y1, 0xa);
__m256d y4 = _mm256_movedup_pd(b.v);
y4 = _mm256_mul_pd(a.v, y4);
__m256d y0 = _mm256_movedup_pd(a.v);
y0 = _mm256_mul_pd(b.v, y0);
y0 = _mm256_sub_pd(y4, y0);
y0 = _mm256_blend_pd(y1, y0, 0xa);
y0 = _mm256_add_pd(y2, y0);
y2 = _mm256_blend_pd(b.v, y1, 0xa);
__m256d y3 = _mm256_mul_pd(b.v, b.v);
y1 = _mm256_unpacklo_pd(y1, y3);
y1 = _mm256_add_pd(y2, y1);
return Packet2dd(_mm256_div_pd(y0, y1));
#else
const __m256d mask = _mm256_castsi256_pd(_mm256_setr_epi32(0xffffffff,0xffffffff,0x00000000,0x00000000,
0xffffffff,0xffffffff,0x00000000,0x00000000));
return Packet2dd(_mm256_div_pd
(_mm256_add_pd(_mm256_and_pd(mask, a.v),
_mm256_andnot_pd(mask,
_mm256_sub_pd(_mm256_mul_pd(a.v,
_mm256_shuffle_pd(b.v,b.v,0x0)),
_mm256_mul_pd(b.v,
_mm256_shuffle_pd(a.v,a.v,0x0))))),
_mm256_add_pd(_mm256_and_pd(mask, b.v),
_mm256_andnot_pd(mask,
_mm256_mul_pd(_mm256_shuffle_pd(b.v,b.v,0x0),
_mm256_shuffle_pd(b.v,b.v,0x0))))));
#endif
}
EIGEN_DEVICE_FUNC inline void
ptranspose(PacketBlock<Packet4df,4>& kernel) {
__m256d P0 = _mm256_castps_pd(kernel.packet[0].v);
__m256d P1 = _mm256_castps_pd(kernel.packet[1].v);
__m256d P2 = _mm256_castps_pd(kernel.packet[2].v);
__m256d P3 = _mm256_castps_pd(kernel.packet[3].v);
__m256d T0 = _mm256_shuffle_pd(P0, P1, 15);
__m256d T1 = _mm256_shuffle_pd(P0, P1, 0);
__m256d T2 = _mm256_shuffle_pd(P2, P3, 15);
__m256d T3 = _mm256_shuffle_pd(P2, P3, 0);
kernel.packet[1].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T0, T2, 32));
kernel.packet[3].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T0, T2, 49));
kernel.packet[0].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T1, T3, 32));
kernel.packet[2].v = _mm256_castpd_ps(_mm256_permute2f128_pd(T1, T3, 49));
}
EIGEN_DEVICE_FUNC inline void
ptranspose(PacketBlock<Packet2dd,2>& kernel) {
__m256d tmp = _mm256_permute2f128_pd(kernel.packet[0].v, kernel.packet[1].v, 0+(2<<4));
kernel.packet[1].v = _mm256_permute2f128_pd(kernel.packet[0].v, kernel.packet[1].v, 1+(3<<4));
kernel.packet[0].v = tmp;
}
template<> EIGEN_STRONG_INLINE Packet4df pinsertfirst(const Packet4df& a, duals::dual<float> b)
{
return Packet4df(_mm256_blend_ps(a.v,pset1<Packet4df>(b).v,1|2));
}
template<> EIGEN_STRONG_INLINE Packet2dd pinsertfirst(const Packet2dd& a, duals::dual<double> b)
{
return Packet2dd(_mm256_blend_pd(a.v,pset1<Packet2dd>(b).v,1|2));
}
template<> EIGEN_STRONG_INLINE Packet4df pinsertlast(const Packet4df& a, duals::dual<float> b)
{
return Packet4df(_mm256_blend_ps(a.v,pset1<Packet4df>(b).v,(1<<7)|(1<<6)));
}
template<> EIGEN_STRONG_INLINE Packet2dd pinsertlast(const Packet2dd& a, duals::dual<double> b)
{
return Packet2dd(_mm256_blend_pd(a.v,pset1<Packet2dd>(b).v,(1<<3)|(1<<2)));
}
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_DUAL_AVX_H

229
src/include/cppduals/duals/arch/SSE/ComplexDual.h

@ -0,0 +1,229 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2019 Michael Tesch <tesch1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_CDUAL_SSE_H
#define EIGEN_CDUAL_SSE_H
namespace Eigen {
namespace internal {
//---------- float ----------
struct Packet1cdf
{
EIGEN_STRONG_INLINE Packet1cdf() {}
EIGEN_STRONG_INLINE explicit Packet1cdf(const __m128 & a) : v(a) {}
EIGEN_STRONG_INLINE explicit Packet1cdf(const Packet2df & a) : v(a) {}
//__m128 v;
Packet2df v;
};
// Use the packet_traits defined in AVX/ComplexDual.h instead if we're
// going to leverage AVX instructions.
#if !defined(CPPDUALS_DONT_VECTORIZE_CDUAL)
#if !defined(EIGEN_VECTORIZE_AVX)
template<> struct packet_traits<std::complex<duals::dual<float> > > : default_packet_traits
{
typedef Packet1cdf type;
typedef Packet1cdf half;
enum {
Vectorizable = 1,
AlignedOnScalar = 0,
size = 1,
HasHalfPacket = 0,
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0
};
};
#endif
#endif
template<> struct unpacket_traits<Packet1cdf> {
typedef std::complex<duals::dual<float> > type;
enum {size=1, alignment=Aligned16, masked_load_available=false, masked_store_available=false, vectorizable=true};
typedef Packet1cdf half;
};
template<> EIGEN_STRONG_INLINE Packet1cdf padd<Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{ return Packet1cdf(_mm_add_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf psub<Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{ return Packet1cdf(_mm_sub_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf pnegate(const Packet1cdf& a) { return Packet1cdf(pnegate(a.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf pconj(const Packet1cdf& a)
{
const __m128 mask = _mm_castsi128_ps(_mm_set_epi32(0x80000000,0x80000000,0x0,0x0));
return Packet1cdf(_mm_xor_ps(a.v.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet1cdf pmul<Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{
#if 1 // defined(EIGEN_VECTORIZE_SSE3)
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0x00000000,0xffffffff,0xffffffff));
return Packet1cdf(vec4f_swizzle1
(_mm_addsub_ps(_mm_add_ps(_mm_mul_ps(vec4f_swizzle1(a.v.v, 0, 0, 0, 0),
vec4f_swizzle1(b.v.v, 0, 2, 1, 3)),
_mm_and_ps(mask,
_mm_mul_ps(vec4f_swizzle1(a.v.v, 0, 0, 1, 1),
vec4f_swizzle1(b.v.v, 0, 0, 0, 2)))),
_mm_add_ps(_mm_mul_ps(vec4f_swizzle1(a.v.v, 2, 2, 2, 2),
vec4f_swizzle1(b.v.v, 2, 0, 3, 1)),
_mm_and_ps(mask,
_mm_mul_ps(vec4f_swizzle1(a.v.v, 0, 0, 3, 3),
vec4f_swizzle1(b.v.v, 0, 0, 2, 0))))),
0,2,1,3));
#else
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0xffffffff,0x00000000,0xffffffff));
const __m128 nega = _mm_castsi128_ps(_mm_setr_epi32(0x80000000,0x80000000,0x00000000,0x00000000));
return Packet1cdf(_mm_add_ps(_mm_add_ps(_mm_mul_ps(vec4f_swizzle1(a.v.v, 0, 0, 0, 0),
vec4f_swizzle1(b.v.v, 0, 1, 2, 3)),
_mm_and_ps(mask,
_mm_mul_ps(vec4f_swizzle1(a.v.v, 0, 1, 0, 1),
vec4f_swizzle1(b.v.v, 0, 0, 0, 2)))),
_mm_xor_ps
(nega,
_mm_add_ps(_mm_mul_ps(vec4f_swizzle1(a.v.v, 2, 2, 2, 2),
vec4f_swizzle1(b.v.v, 2, 3, 0, 1)),
_mm_and_ps(mask,
_mm_mul_ps(vec4f_swizzle1(a.v.v, 0, 3, 0, 3),
vec4f_swizzle1(b.v.v, 0, 2, 0, 0)))))));
#endif
return a;
}
template<> EIGEN_STRONG_INLINE Packet1cdf pand <Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{ return Packet1cdf(_mm_and_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf por <Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{ return Packet1cdf(_mm_or_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf pxor <Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{ return Packet1cdf(_mm_xor_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf pandnot<Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{ return Packet1cdf(_mm_andnot_ps(a.v.v,b.v.v)); }
template<> EIGEN_STRONG_INLINE Packet1cdf pload <Packet1cdf>(const std::complex<duals::dual<float> >* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet1cdf(ploadu<Packet4f>((const float*)from)); }
template<> EIGEN_STRONG_INLINE Packet1cdf ploadu<Packet1cdf>(const std::complex<duals::dual<float> >* from)
{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cdf(ploadu<Packet4f>((const float*)from)); }
template<> EIGEN_STRONG_INLINE Packet1cdf pset1<Packet1cdf>(const std::complex<duals::dual<float> >& from)
{ /* here we really have to use unaligned loads :( */ return ploadu<Packet1cdf>(&from); }
template<> EIGEN_STRONG_INLINE Packet1cdf ploaddup<Packet1cdf>(const std::complex<duals::dual<float> >* from)
{ return pset1<Packet1cdf>(*from); }
// FIXME force unaligned store, this is a temporary fix
template<> EIGEN_STRONG_INLINE void
pstore <std::complex<duals::dual<float> > >(std::complex<duals::dual<float> > * to, const Packet1cdf& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstoreu((float*)to, from.v.v); }
template<> EIGEN_STRONG_INLINE void
pstoreu<std::complex<duals::dual<float> > >(std::complex<duals::dual<float> > * to, const Packet1cdf& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v.v); }
template<> EIGEN_STRONG_INLINE void
prefetch<std::complex<duals::dual<float> > >(const std::complex<duals::dual<float> > * addr)
{ _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<float> > pfirst<Packet1cdf>(const Packet1cdf& a)
{
EIGEN_ALIGN16 float res[4];
_mm_store_ps(res, a.v.v);
return std::complex<duals::dual<float> >(duals::dual<float>(res[0],res[1]),
duals::dual<float>(res[2],res[3]));
}
template<> EIGEN_STRONG_INLINE Packet1cdf preverse(const Packet1cdf& a) { return a; }
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<float> > predux<Packet1cdf>(const Packet1cdf& a)
{
return pfirst(a);
}
template<> EIGEN_STRONG_INLINE Packet1cdf preduxp<Packet1cdf>(const Packet1cdf* vecs)
{
return vecs[0];
}
template<> EIGEN_STRONG_INLINE std::complex<duals::dual<float> > predux_mul<Packet1cdf>(const Packet1cdf& a)
{
return pfirst(a);
}
template<int Offset>
struct palign_impl<Offset,Packet1cdf>
{
static EIGEN_STRONG_INLINE void run(Packet1cdf& /*first*/, const Packet1cdf& /*second*/)
{
// FIXME is it sure we never have to align a Packet1cdf?
// Even though a std::complex<duals::dual<float> > has 16 bytes, it is not necessarily aligned on a 16 bytes boundary...
}
};
template<> struct conj_helper<Packet1cdf, Packet1cdf, false,true>
{
EIGEN_STRONG_INLINE Packet1cdf pmadd(const Packet1cdf& x, const Packet1cdf& y, const Packet1cdf& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1cdf pmul(const Packet1cdf& a, const Packet1cdf& b) const
{
return internal::pmul(a, pconj(b));
}
};
template<> struct conj_helper<Packet1cdf, Packet1cdf, true,false>
{
EIGEN_STRONG_INLINE Packet1cdf pmadd(const Packet1cdf& x, const Packet1cdf& y, const Packet1cdf& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1cdf pmul(const Packet1cdf& a, const Packet1cdf& b) const
{
return internal::pmul(pconj(a), b);
}
};
template<> struct conj_helper<Packet1cdf, Packet1cdf, true,true>
{
EIGEN_STRONG_INLINE Packet1cdf pmadd(const Packet1cdf& x, const Packet1cdf& y, const Packet1cdf& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1cdf pmul(const Packet1cdf& a, const Packet1cdf& b) const
{
return pconj(internal::pmul(a, b));
}
};
//TODO
EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cdf,Packet2df)
template<> EIGEN_STRONG_INLINE Packet1cdf pdiv<Packet1cdf>(const Packet1cdf& a, const Packet1cdf& b)
{
Packet1cdf res = conj_helper<Packet1cdf,Packet1cdf,false,true>().pmul(a,b);
Packet2df s = pmul(b.v, b.v);
return Packet1cdf(pdiv(res.v,
padd(s, Packet2df(_mm_castpd_ps(_mm_shuffle_pd(_mm_castps_pd(s.v),
_mm_castps_pd(s.v), 0x1))))));
}
EIGEN_STRONG_INLINE Packet1cdf pcplxflip/* <Packet1cdf> */(const Packet1cdf& x)
{
return Packet1cdf(vec4f_swizzle1(x.v.v, 2, 3, 0, 1));
}
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_CDUAL_SSE_H

459
src/include/cppduals/duals/arch/SSE/Dual.h

@ -0,0 +1,459 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2019 Michael Tesch <tesch1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_DUAL_SSE_H
#define EIGEN_DUAL_SSE_H
namespace Eigen {
namespace internal {
//---------- float ----------
struct Packet2df
{
EIGEN_STRONG_INLINE Packet2df() {}
EIGEN_STRONG_INLINE explicit Packet2df(const __m128& a) : v(a) {}
__m128 v;
};
// Use the packet_traits defined in AVX/Dual.h instead if we're going
// to leverage AVX instructions.
#ifndef EIGEN_VECTORIZE_AVX
template<> struct packet_traits<duals::dual<float> > : default_packet_traits
{
typedef Packet2df type;
typedef Packet2df half;
enum {
Vectorizable = 1,
AlignedOnScalar = 1,
size = 2,
HasHalfPacket = 0,
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0,
HasBlend = 1
};
};
#endif
template<> struct unpacket_traits<Packet2df> {
typedef duals::dual<float> type;
enum {size=2, alignment=Aligned16, masked_load_available=false, masked_store_available=false, vectorizable=true};
typedef Packet2df half;
};
template<> EIGEN_STRONG_INLINE Packet2df padd<Packet2df>(const Packet2df& a, const Packet2df& b)
{ return Packet2df(_mm_add_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2df psub<Packet2df>(const Packet2df& a, const Packet2df& b)
{ return Packet2df(_mm_sub_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2df pnegate(const Packet2df& a)
{
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x80000000,0x80000000,0x80000000,0x80000000));
return Packet2df(_mm_xor_ps(a.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet2df pdconj(const Packet2df& a)
{
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0x80000000,0x00000000,0x80000000));
return Packet2df(_mm_xor_ps(a.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet2df pconj(const Packet2df& a) { return a; }
template<> EIGEN_STRONG_INLINE Packet2df pmul<Packet2df>(const Packet2df& a, const Packet2df& b)
{
#if defined(EIGEN_VECTORIZE_SSE3)
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0xffffffff,0x00000000,0xffffffff));
return Packet2df(_mm_add_ps(_mm_and_ps(mask, _mm_mul_ps(a.v, _mm_moveldup_ps(b.v))),
_mm_mul_ps(b.v, _mm_moveldup_ps(a.v))));
#else
//TODO-use avx instructions instead?
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0x00000000,0xffffffff,0x00000000,0xffffffff));
return Packet2df(_mm_add_ps(_mm_and_ps(mask, _mm_mul_ps(a.v, _mm_moveldup_ps(b.v))),
_mm_mul_ps(b.v, _mm_moveldup_ps(a.v))));
#endif
}
template<> EIGEN_STRONG_INLINE Packet2df pand <Packet2df>(const Packet2df& a, const Packet2df& b)
{ return Packet2df(_mm_and_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2df por <Packet2df>(const Packet2df& a, const Packet2df& b)
{ return Packet2df(_mm_or_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2df pxor <Packet2df>(const Packet2df& a, const Packet2df& b)
{ return Packet2df(_mm_xor_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2df pandnot<Packet2df>(const Packet2df& a, const Packet2df& b)
{ return Packet2df(_mm_andnot_ps(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet2df pload <Packet2df>(const duals::dual<float>* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet2df(pload<Packet4f>(&numext::real_ref(*from))); }
template<> EIGEN_STRONG_INLINE Packet2df ploadu<Packet2df>(const duals::dual<float>* from)
{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet2df(ploadu<Packet4f>(&numext::real_ref(*from))); }
template<> EIGEN_STRONG_INLINE Packet2df pset1<Packet2df>(const duals::dual<float>& from)
{
Packet2df res;
#if EIGEN_GNUC_AT_MOST(4,2)
// Workaround annoying "may be used uninitialized in this function" warning with gcc 4.2
res.v = _mm_loadl_pi(_mm_set1_ps(0.0f), reinterpret_cast<const __m64*>(&from));
#elif EIGEN_GNUC_AT_LEAST(4,6)
// Suppress annoying "may be used uninitialized in this function" warning with gcc >= 4.6
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
res.v = _mm_loadl_pi(res.v, (const __m64*)&from);
#pragma GCC diagnostic pop
#else
res.v = _mm_loadl_pi(res.v, (const __m64*)&from);
#endif
return Packet2df(_mm_movelh_ps(res.v,res.v));
}
template<> EIGEN_STRONG_INLINE Packet2df ploaddup<Packet2df>(const duals::dual<float>* from)
{ return pset1<Packet2df>(*from); }
template<> EIGEN_STRONG_INLINE void pstore <duals::dual<float> >(duals::dual<float> * to, const Packet2df& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstore(&numext::real_ref(*to), Packet4f(from.v)); }
template<> EIGEN_STRONG_INLINE void pstoreu<duals::dual<float> >(duals::dual<float> * to, const Packet2df& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&numext::real_ref(*to), Packet4f(from.v)); }
template<> EIGEN_DEVICE_FUNC inline Packet2df pgather<duals::dual<float>, Packet2df>(const duals::dual<float>* from,
Index stride)
{
return Packet2df(_mm_set_ps(duals::dpart(from[1*stride]), duals::rpart(from[1*stride]),
duals::dpart(from[0*stride]), duals::rpart(from[0*stride])));
}
template<> EIGEN_DEVICE_FUNC inline void pscatter<duals::dual<float>, Packet2df>(duals::dual<float>* to,
const Packet2df& from, Index stride)
{
to[stride*0] = duals::dual<float>(_mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 0)),
_mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 1)));
to[stride*1] = duals::dual<float>(_mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 2)),
_mm_cvtss_f32(_mm_shuffle_ps(from.v, from.v, 3)));
}
template<> EIGEN_STRONG_INLINE void prefetch<duals::dual<float> >(const duals::dual<float> * addr)
{ _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
template<> EIGEN_STRONG_INLINE duals::dual<float> pfirst<Packet2df>(const Packet2df& a)
{
#if EIGEN_GNUC_AT_MOST(4,3)
// Workaround gcc 4.2 ICE - this is not performance wise ideal, but who cares...
// This workaround also fix invalid code generation with gcc 4.3
EIGEN_ALIGN16 duals::dual<float> res[2];
_mm_store_ps((float*)res, a.v);
return res[0];
#else
duals::dual<float> res;
_mm_storel_pi((__m64*)&res, a.v);
return res;
#endif
}
template<> EIGEN_STRONG_INLINE Packet2df preverse(const Packet2df& a)
{ return Packet2df(_mm_castpd_ps(preverse(Packet2d(_mm_castps_pd(a.v))))); }
template<> EIGEN_STRONG_INLINE duals::dual<float> predux<Packet2df>(const Packet2df& a)
{
return pfirst(Packet2df(_mm_add_ps(a.v, _mm_movehl_ps(a.v,a.v))));
}
template<> EIGEN_STRONG_INLINE Packet2df preduxp<Packet2df>(const Packet2df* vecs)
{
return Packet2df(_mm_add_ps(_mm_movelh_ps(vecs[0].v,vecs[1].v),
_mm_movehl_ps(vecs[1].v,vecs[0].v)));
}
template<> EIGEN_STRONG_INLINE duals::dual<float> predux_mul<Packet2df>(const Packet2df& a)
{
return pfirst(pmul(a, Packet2df(_mm_movehl_ps(a.v,a.v))));
}
template<int Offset>
struct palign_impl<Offset,Packet2df>
{
static EIGEN_STRONG_INLINE void run(Packet2df& first, const Packet2df& second)
{
if (Offset==1)
{
first.v = _mm_movehl_ps(first.v, first.v);
first.v = _mm_movelh_ps(first.v, second.v);
}
}
};
#if 0 // TODO
template<> struct dconj_helper<Packet2df, Packet2df, false,true>
{
EIGEN_STRONG_INLINE Packet2df pmadd(const Packet2df& x, const Packet2df& y, const Packet2df& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2df pmul(const Packet2df& a, const Packet2df& b) const
{ return internal::pmul(a, pdconj(b)); }
};
template<> struct dconj_helper<Packet2df, Packet2df, true,false>
{
EIGEN_STRONG_INLINE Packet2df pmadd(const Packet2df& x, const Packet2df& y, const Packet2df& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2df pmul(const Packet2df& a, const Packet2df& b) const
{ return internal::pmul(pdconj(a), b); }
};
template<> struct dconj_helper<Packet2df, Packet2df, true,true>
{
EIGEN_STRONG_INLINE Packet2df pmadd(const Packet2df& x, const Packet2df& y, const Packet2df& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet2df pmul(const Packet2df& a, const Packet2df& b) const
{ return pdconj(internal::pmul(a, b)); }
};
EIGEN_MAKE_DCONJ_HELPER_DUAL_REAL(Packet2df,Packet4f)
#endif
template<> EIGEN_STRONG_INLINE Packet2df pdiv<Packet2df>(const Packet2df& a, const Packet2df& b)
{
// TODO optimize it for SSE3 and 4
const __m128 mask = _mm_castsi128_ps(_mm_setr_epi32(0xffffffff,0x00000000,0xffffffff,0x00000000));
return Packet2df(_mm_div_ps(_mm_add_ps(_mm_and_ps(mask, a.v),
_mm_andnot_ps(mask,
_mm_sub_ps(_mm_mul_ps(a.v, vec4f_swizzle1(b.v, 0, 0, 2, 2)),
_mm_mul_ps(b.v, vec4f_swizzle1(a.v, 0, 0, 2, 2))))),
_mm_add_ps(_mm_and_ps(mask, b.v),
_mm_andnot_ps(mask,
_mm_mul_ps(vec4f_swizzle1(b.v, 0, 0, 2, 2),
vec4f_swizzle1(b.v, 0, 0, 2, 2))))));
}
//---------- double ----------
struct Packet1dd
{
EIGEN_STRONG_INLINE Packet1dd() {}
EIGEN_STRONG_INLINE explicit Packet1dd(const __m128d& a) : v(a) {}
__m128d v;
};
// Use the packet_traits defined in AVX/PacketMath.h instead if we're going
// to leverage AVX instructions.
#ifndef EIGEN_VECTORIZE_AVX
template<> struct packet_traits<duals::dual<double> > : default_packet_traits
{
typedef Packet1dd type;
typedef Packet1dd half;
enum {
Vectorizable = 1,
AlignedOnScalar = 0,
size = 1,
HasHalfPacket = 0,
HasAdd = 1,
HasSub = 1,
HasMul = 1,
HasDiv = 1,
HasNegate = 1,
HasAbs = 0,
HasAbs2 = 0,
HasMin = 0,
HasMax = 0,
HasSetLinear = 0
};
};
#endif
template<> struct unpacket_traits<Packet1dd> {
typedef duals::dual<double> type;
enum {size=1, alignment=Aligned16, masked_load_available=false, masked_store_available=false, vectorizable=true};
typedef Packet1dd half;
};
template<> EIGEN_STRONG_INLINE Packet1dd padd<Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{ return Packet1dd(_mm_add_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet1dd psub<Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{ return Packet1dd(_mm_sub_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet1dd pnegate(const Packet1dd& a) { return Packet1dd(pnegate(Packet2d(a.v))); }
template<> EIGEN_STRONG_INLINE Packet1dd pdconj(const Packet1dd& a)
{
const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x80000000,0x0,0x0,0x0));
return Packet1dd(_mm_xor_pd(a.v,mask));
}
template<> EIGEN_STRONG_INLINE Packet1dd pconj(const Packet1dd& a) { return a; }
template<> EIGEN_STRONG_INLINE Packet1dd pmul<Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{
//#ifdef EIGEN_VECTORIZE_SSE3
//TODO
const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0xffffffff,0xffffffff,0x00000000,0x00000000));
return Packet1dd(_mm_add_pd(_mm_and_pd(mask,
_mm_mul_pd(vec2d_swizzle1(a.v, 0, 1),
vec2d_swizzle1(b.v, 0, 0))),
_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0),
vec2d_swizzle1(b.v, 0, 1))));
//#else
//#endif
}
template<> EIGEN_STRONG_INLINE Packet1dd pand <Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{ return Packet1dd(_mm_and_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet1dd por <Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{ return Packet1dd(_mm_or_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet1dd pxor <Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{ return Packet1dd(_mm_xor_pd(a.v,b.v)); }
template<> EIGEN_STRONG_INLINE Packet1dd pandnot<Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{ return Packet1dd(_mm_andnot_pd(a.v,b.v)); }
// FIXME force unaligned load, this is a temporary fix
template<> EIGEN_STRONG_INLINE Packet1dd pload <Packet1dd>(const duals::dual<double>* from)
{ EIGEN_DEBUG_ALIGNED_LOAD return Packet1dd(pload<Packet2d>((const double*)from)); }
template<> EIGEN_STRONG_INLINE Packet1dd ploadu<Packet1dd>(const duals::dual<double>* from)
{ EIGEN_DEBUG_UNALIGNED_LOAD return Packet1dd(ploadu<Packet2d>((const double*)from)); }
template<> EIGEN_STRONG_INLINE Packet1dd pset1<Packet1dd>(const duals::dual<double>& from)
{ /* here we really have to use unaligned loads :( */ return ploadu<Packet1dd>(&from); }
template<> EIGEN_STRONG_INLINE Packet1dd ploaddup<Packet1dd>(const duals::dual<double>* from)
{ return pset1<Packet1dd>(*from); }
// FIXME force unaligned store, this is a temporary fix
template<> EIGEN_STRONG_INLINE void pstore <duals::dual<double> >(duals::dual<double> * to, const Packet1dd& from)
{ EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, Packet2d(from.v)); }
template<> EIGEN_STRONG_INLINE void pstoreu<duals::dual<double> >(duals::dual<double> * to, const Packet1dd& from)
{ EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, Packet2d(from.v)); }
template<> EIGEN_STRONG_INLINE void prefetch<duals::dual<double> >(const duals::dual<double> * addr)
{ _mm_prefetch((SsePrefetchPtrType)(addr), _MM_HINT_T0); }
template<> EIGEN_STRONG_INLINE duals::dual<double> pfirst<Packet1dd>(const Packet1dd& a)
{
EIGEN_ALIGN16 double res[2];
_mm_store_pd(res, a.v);
return duals::dual<double>(res[0],res[1]);
}
template<> EIGEN_STRONG_INLINE Packet1dd preverse(const Packet1dd& a) { return a; }
template<> EIGEN_STRONG_INLINE duals::dual<double> predux<Packet1dd>(const Packet1dd& a)
{
return pfirst(a);
}
template<> EIGEN_STRONG_INLINE Packet1dd preduxp<Packet1dd>(const Packet1dd* vecs)
{
return vecs[0];
}
template<> EIGEN_STRONG_INLINE duals::dual<double> predux_mul<Packet1dd>(const Packet1dd& a)
{
return pfirst(a);
}
template<int Offset>
struct palign_impl<Offset,Packet1dd>
{
static EIGEN_STRONG_INLINE void run(Packet1dd& /*first*/, const Packet1dd& /*second*/)
{
// FIXME is it sure we never have to align a Packet1dd?
// Even though a duals::dual<double> has 16 bytes, it is not necessarily aligned on a 16 bytes boundary...
}
};
#if 0 // TODO
template<> struct dconj_helper<Packet1dd, Packet1dd, false,true>
{
EIGEN_STRONG_INLINE Packet1dd pmadd(const Packet1dd& x, const Packet1dd& y, const Packet1dd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1dd pmul(const Packet1dd& a, const Packet1dd& b) const
{ return internal::pmul(a, pdconj(b)); }
};
template<> struct dconj_helper<Packet1dd, Packet1dd, true,false>
{
EIGEN_STRONG_INLINE Packet1dd pmadd(const Packet1dd& x, const Packet1dd& y, const Packet1dd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1dd pmul(const Packet1dd& a, const Packet1dd& b) const
{ return internal::pmul(pdconj(a), b); }
};
template<> struct dconj_helper<Packet1dd, Packet1dd, true,true>
{
EIGEN_STRONG_INLINE Packet1dd pmadd(const Packet1dd& x, const Packet1dd& y, const Packet1dd& c) const
{ return padd(pmul(x,y),c); }
EIGEN_STRONG_INLINE Packet1dd pmul(const Packet1dd& a, const Packet1dd& b) const
{ return pdconj(internal::pmul(a, b)); }
};
EIGEN_MAKE_DCONJ_HELPER_DUAL_REAL(Packet1dd,Packet2d)
#endif
template<> EIGEN_STRONG_INLINE Packet1dd pdiv<Packet1dd>(const Packet1dd& a, const Packet1dd& b)
{
// TODO optimize it for SSE3 and 4
//const __m128d mask = _mm_castsi128_pd(_mm_set_epi32(0x0,0x0,0x80000000,0x0));
//return Packet1cd(_mm_add_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0), b.v),
// _mm_xor_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 1, 1),
// vec2d_swizzle1(b.v, 1, 0)), mask)));
// TODO optimize it for SSE3 and 4
const __m128d mask = _mm_castsi128_pd(_mm_setr_epi32(0xffffffff,0xffffffff,0x00000000,0x00000000));
return Packet1dd(_mm_div_pd(_mm_add_pd(_mm_and_pd(mask, a.v),
_mm_andnot_pd(mask,
_mm_sub_pd(_mm_mul_pd(vec2d_swizzle1(a.v, 0, 1),
vec2d_swizzle1(b.v, 0, 0)),
_mm_mul_pd(vec2d_swizzle1(a.v, 0, 0),
vec2d_swizzle1(b.v, 0, 1))))),
_mm_add_pd(_mm_and_pd(mask, b.v),
_mm_andnot_pd(mask,
_mm_mul_pd(vec2d_swizzle1(b.v, 0, 0),
vec2d_swizzle1(b.v, 0, 0))))));
}
EIGEN_DEVICE_FUNC inline void
ptranspose(PacketBlock<Packet2df,2>& kernel) {
__m128d w1 = _mm_castps_pd(kernel.packet[0].v);
__m128d w2 = _mm_castps_pd(kernel.packet[1].v);
__m128 tmp = _mm_castpd_ps(_mm_unpackhi_pd(w1, w2));
kernel.packet[0].v = _mm_castpd_ps(_mm_unpacklo_pd(w1, w2));
kernel.packet[1].v = tmp;
}
template<> EIGEN_STRONG_INLINE Packet2df pblend(const Selector<2>& ifPacket,
const Packet2df& thenPacket,
const Packet2df& elsePacket)
{
__m128d result = pblend<Packet2d>(ifPacket, _mm_castps_pd(thenPacket.v), _mm_castps_pd(elsePacket.v));
return Packet2df(_mm_castpd_ps(result));
}
template<> EIGEN_STRONG_INLINE Packet2df pinsertfirst(const Packet2df& a, duals::dual<float> b)
{
return Packet2df(_mm_loadl_pi(a.v, reinterpret_cast<const __m64*>(&b)));
}
template<> EIGEN_STRONG_INLINE Packet1dd pinsertfirst(const Packet1dd&, duals::dual<double> b)
{
return pset1<Packet1dd>(b);
}
template<> EIGEN_STRONG_INLINE Packet2df pinsertlast(const Packet2df& a, duals::dual<float> b)
{
return Packet2df(_mm_loadh_pi(a.v, reinterpret_cast<const __m64*>(&b)));
}
template<> EIGEN_STRONG_INLINE Packet1dd pinsertlast(const Packet1dd&, duals::dual<double> b)
{
return pset1<Packet1dd>(b);
}
} // end namespace internal
} // end namespace Eigen
#endif // EIGEN_COMPLEX_SSE_H

1384
src/include/cppduals/duals/dual
File diff suppressed because it is too large
View File

774
src/include/cppduals/duals/dual_eigen

@ -0,0 +1,774 @@
//===-- duals/dual_eigen - wrapp dual number type for Eigen -----*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Some code fragments are adapted from Eigen's Complex.h files, which
// carry the following license:
//
// Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef CPPDUALS_DUAL_EIGEN
#define CPPDUALS_DUAL_EIGEN
#include "dual"
#ifndef PARSED_BY_DOXYGEN
#include <complex>
#include <Eigen/Core>
#endif
#if !EIGEN_VERSION_AT_LEAST(3, 3, 0)
#error "Eigen too old for cppduals. Upgrade."
#endif
/** \file dual_eigen
\brief Nestable, vectorizable Dual numbers for Eigen
Include this file to enable use of the `duals::dual<>` class as a
scalar type in Eigen. Some optimizations are performed using
Eigen's vectorization facilities, which is particularly noticeable
for multiplication and division. In certain cases the
vectorization can be worse than the compiler's code, thus it can
be disabled by `#define CPPDUALS_DONT_VECTORIZE`.
There is some also vectorization for dual-ized complex's
(`std::complex<duals::dual<T>>`), which can be disabled by
`#define CPPDUALS_DONT_VECTORIZE_CDUAL`.
The same type promotion that exists for `duals::dual<T>`: an
operation between a 'scalar' T and dual<T> is promoted to dual<T>.
This is enabled for Eigen matrices by default: multiplying an
`Eigen::Matrix<float>` by `1_ef` results in an expression with a
basic POD type of `Eigen::Matrix<duals::dual<float>,..>`. This
type of type promotion can be disabled (ie for correctness
checking or to speed compilation) by #define
`CPPDUALS_NO_EIGEN_PROMOTION`.
*/
namespace duals {
/** template unary functor to get the real part of a matrix
* use it like this: m2 = m1.unaryExpr(CwiseRpartOp<double>());
* or just call m2 = rpart(m1);
*/
template<typename ScalarSrc>
struct CwiseRpartOp {
typedef decltype(rpart(ScalarSrc())) ScalarDst;
typedef ScalarDst result_type;
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE ScalarDst operator()(const ScalarSrc & x) const { return rpart(x); }
};
/** template unary functor to get the dual part of a matrix
* use it like this: m2 = m1.unaryExpr(CwiseDpartOp<double>());
* or just call m2 = dpart(m1);
*/
template<typename ScalarSrc>
struct CwiseDpartOp {
typedef decltype(dpart(ScalarSrc())) ScalarDst;
typedef ScalarDst result_type;
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE ScalarDst operator()(const ScalarSrc & x) const { return dpart(x); }
};
/** template unary functor to dual-conjugate a matrix of duals
* use it like this: m2 = m1.unaryExpr(CwiseDconjOp<double>());
* or just call m2 = dconj(m1);
*/
template<typename Scalar>
struct CwiseDconjOp {
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Scalar operator()(const Scalar & x) const { return dconj(x); }
};
/// Extract the "real part" of a dual-valued matrix.
#ifdef PARSED_BY_DOXYGEN
template <typename XprType> const RealType
#else
template <typename XprType>
const Eigen::CwiseUnaryOp<CwiseRpartOp<typename XprType::Scalar>, const XprType >
#endif
rpart(const Eigen::EigenBase<XprType> & x)
{
return x.derived().unaryExpr(CwiseRpartOp<typename XprType::Scalar>());
}
/// Extract the "dual part" of a dual-valued matrix.
#ifdef PARSED_BY_DOXYGEN
template <typename XprType> const RealType
#else
template <typename XprType>
const Eigen::CwiseUnaryOp<CwiseDpartOp<typename XprType::Scalar>, const XprType >
#endif
dpart(const Eigen::EigenBase<XprType> & x)
{
return x.derived().unaryExpr(CwiseDpartOp<typename XprType::Scalar>());
}
/// Dual-conjugate a dual-valued matrix.
#ifdef PARSED_BY_DOXYGEN
template <typename XprType> const XprType
#else
template <typename XprType>
const Eigen::CwiseUnaryOp<CwiseDconjOp<typename XprType::Scalar>, const XprType >
#endif
dconj(const Eigen::EigenBase<XprType> & x)
{
return x.derived().unaryExpr(CwiseDconjOp<typename XprType::Scalar>());
}
} // namespace duals
namespace Eigen {
template<typename T>
struct NumTraits<duals::dual<T> > : GenericNumTraits<T>
{
typedef typename NumTraits<T>::Real ReallyReal;
typedef duals::dual<T> Real;
typedef duals::dual<T> Literal;
typedef duals::dual<T> Nested;
enum {
IsInteger = NumTraits<T>::IsInteger,
IsSigned = NumTraits<T>::IsSigned,
IsComplex = 0,
RequireInitialization = NumTraits<T>::RequireInitialization,
ReadCost = 2 * NumTraits<T>::ReadCost,
AddCost = 2 * NumTraits<T>::AddCost,
MulCost = 3 * NumTraits<T>::MulCost + 1 * NumTraits<T>::AddCost
};
EIGEN_DEVICE_FUNC
static inline Real epsilon() { return Real(NumTraits<T>::epsilon()); }
EIGEN_DEVICE_FUNC
static inline ReallyReal dummy_precision() { return NumTraits<T>::dummy_precision(); }
EIGEN_DEVICE_FUNC
static inline ReallyReal highest() { return NumTraits<T>::highest(); }
EIGEN_DEVICE_FUNC
static inline ReallyReal lowest() { return NumTraits<T>::lowest(); }
EIGEN_DEVICE_FUNC
static inline ReallyReal digits10() { return NumTraits<T>::digits10(); }
};
#if !defined(CPPDUALS_NO_EIGEN_PROMOTION)
template<typename T, typename BinaryOp>
struct ScalarBinaryOpTraits<duals::dual<T>,duals::dual<T>,BinaryOp>
: public duals::can_promote<duals::dual<T>,duals::dual<T>>::wrap {};
template<typename T, typename BinaryOp>
struct ScalarBinaryOpTraits<duals::dual<T>,T,BinaryOp>
: public duals::can_promote<duals::dual<T>,T>::wrap {};
template<typename T, typename BinaryOp>
struct ScalarBinaryOpTraits<T,duals::dual<T>,BinaryOp>
: public duals::can_promote<duals::dual<T>,T>::wrap {};
#if 0 // until Eigen doesnt make assumptions about complex return types :P
template<typename T, typename BinaryOp>
struct ScalarBinaryOpTraits<std::complex<T>,duals::dual<T>,BinaryOp>
: public duals::can_promote<std::complex<T>,duals::dual<T>>::wrap {};
template<typename T, typename BinaryOp>
struct ScalarBinaryOpTraits<duals::dual<T>,std::complex<T>,BinaryOp>
: public duals::can_promote<std::complex<T>,duals::dual<T>>::wrap {};
#endif
#ifndef PARSED_BY_DOXYGEN
// Special cases for nested complex<dual<>> and reals
#define CPPDUALS_CD_SBOTS_REALS(U) \
template<typename T, typename BinaryOp> \
struct ScalarBinaryOpTraits<std::complex<duals::dual<T>>,U,BinaryOp> \
: public duals::can_promote<std::complex<duals::dual<T>>,U>::wrap {}; \
template<typename T, typename BinaryOp> \
struct ScalarBinaryOpTraits<U,std::complex<duals::dual<T>>,BinaryOp> \
: public duals::can_promote<std::complex<duals::dual<T>>,U>::wrap {}
CPPDUALS_CD_SBOTS_REALS(int);
CPPDUALS_CD_SBOTS_REALS(float);
CPPDUALS_CD_SBOTS_REALS(double);
CPPDUALS_CD_SBOTS_REALS(std::complex<T>);
#endif // PARSED_BY_DOXYGEN
#endif // CPPDUALS_NO_EIGEN_PROMOTION
#ifndef PARSED_BY_DOXYGEN
namespace numext {
using duals::rpart;
using duals::dpart;
using duals::dconj;
}
namespace internal {
template<typename T>
struct real_impl<duals::dual<T> >
{
typedef T RealScalar;
EIGEN_DEVICE_FUNC
static inline T run(const duals::dual<T>& x)
{
return x.rpart();
}
};
template<typename Scalar>
struct real_ref_impl<duals::dual<Scalar>>
{
typedef typename NumTraits<Scalar>::Real RealScalar;
EIGEN_DEVICE_FUNC
static inline RealScalar & run(duals::dual<Scalar> & x)
{
return reinterpret_cast<RealScalar*>(&x)[0];
}
EIGEN_DEVICE_FUNC
static inline const RealScalar & run(const duals::dual<Scalar> & x)
{
return reinterpret_cast<const RealScalar *>(&x)[0];
}
};
template<typename Scalar>
struct real_ref_retval<duals::dual<Scalar>>
{
typedef typename NumTraits<Scalar>::Real & type;
};
template<typename T> struct scalar_random_op<duals::dual<T>>
{
EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op)
inline const duals::dual<T> operator() () const { return duals::random<duals::dual<T>>(); }
};
// // stuff for gebp_*
template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
pdconj(const Packet& a) { return numext::dconj(a); }
template<bool Conjugate> struct dconj_if;
template<> struct dconj_if<true> {
template<typename T> inline T operator()(const T& x) const { return numext::dconj(x); }
template<typename T> inline T pdconj(const T& x) const { return internal::pdconj(x); }
};
template<> struct dconj_if<false> {
template<typename T> inline const T& operator()(const T& x) const { return x; }
template<typename T> inline const T& pdconj(const T& x) const { return x; }
};
// Generic implementation for custom dual types.
template<typename LhsScalar, typename RhsScalar, bool ConjLhs, bool ConjRhs>
struct dconj_helper
{
typedef typename ScalarBinaryOpTraits<LhsScalar,RhsScalar>::ReturnType Scalar;
EIGEN_STRONG_INLINE Scalar pmadd(const LhsScalar& x, const RhsScalar& y, const Scalar& c) const
{ return padd(c, pmul(x,y)); }
EIGEN_STRONG_INLINE Scalar pmul(const LhsScalar& x, const RhsScalar& y) const
{ return dconj_if<ConjLhs>()(x) * dconj_if<ConjRhs>()(y); }
};
template<typename Scalar> struct dconj_helper<Scalar,Scalar,false,false>
{
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
{ return internal::pmadd(x,y,c); }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
{ return internal::pmul(x,y); }
};
template<typename RealScalar> struct dconj_helper<duals::dual<RealScalar>, duals::dual<RealScalar>, false,true>
{
typedef duals::dual<RealScalar> Scalar;
EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
{ return c + pmul(x,y); }
EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
{ return Scalar(numext::real(x)*numext::real(y) + numext::imag(x)*numext::imag(y),
numext::imag(x)*numext::real(y) - numext::real(x)*numext::imag(y)); }
};
template<typename RealScalar> struct dconj_helper<duals::dual<RealScalar>, duals::dual<RealScalar>, true,false>
{
typedef duals::dual<RealScalar> Scalar;
EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
{ return c + pmul(x,y); }
EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
{ return Scalar(numext::real(x)*numext::real(y) + numext::imag(x)*numext::imag(y),
numext::real(x)*numext::imag(y) - numext::imag(x)*numext::real(y)); }
};
template<typename RealScalar> struct dconj_helper<duals::dual<RealScalar>, duals::dual<RealScalar>, true,true>
{
typedef duals::dual<RealScalar> Scalar;
EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const Scalar& y, const Scalar& c) const
{ return c + pmul(x,y); }
EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const Scalar& y) const
{ return Scalar(numext::real(x)*numext::real(y) - numext::imag(x)*numext::imag(y),
-numext::real(x)*numext::imag(y) - numext::imag(x)*numext::real(y)); }
};
template<typename RealScalar,bool Conj> struct dconj_helper<duals::dual<RealScalar>, RealScalar, Conj,false>
{
typedef duals::dual<RealScalar> Scalar;
EIGEN_STRONG_INLINE Scalar pmadd(const Scalar& x, const RealScalar& y, const Scalar& c) const
{ return padd(c, pmul(x,y)); }
EIGEN_STRONG_INLINE Scalar pmul(const Scalar& x, const RealScalar& y) const
{ return dconj_if<Conj>()(x)*y; }
};
template<typename RealScalar,bool Conj> struct dconj_helper<RealScalar, duals::dual<RealScalar>, false,Conj>
{
typedef duals::dual<RealScalar> Scalar;
EIGEN_STRONG_INLINE Scalar pmadd(const RealScalar& x, const Scalar& y, const Scalar& c) const
{ return padd(c, pmul(x,y)); }
EIGEN_STRONG_INLINE Scalar pmul(const RealScalar& x, const Scalar& y) const
{ return x*dconj_if<Conj>()(y); }
};
} // namespace internal
#endif // PARSED_BY_DOXYGEN
} // namespace Eigen
#if !defined(CPPDUALS_DONT_VECTORIZE)
#ifndef PARSED_BY_DOXYGEN
// first thing Eigen does: stop the compiler from committing suicide
#include "Eigen/src/Core/util/DisableStupidWarnings.h"
#define EIGEN_MAKE_DCONJ_HELPER_DUAL_REAL(PACKET_DUAL, PACKET_REAL) \
template<> struct dconj_helper<PACKET_REAL, PACKET_DUAL, false,false> { \
EIGEN_STRONG_INLINE PACKET_DUAL pmadd(const PACKET_REAL& x, const PACKET_DUAL& y, const PACKET_DUAL& c) const \
{ return padd(c, pmul(x,y)); } \
EIGEN_STRONG_INLINE PACKET_DUAL pmul(const PACKET_REAL& x, const PACKET_DUAL& y) const \
{ return PACKET_DUAL(Eigen::internal::pmul<PACKET_REAL>(x, PACKET_REAL(y.v))); } \
}; \
\
template<> struct dconj_helper<PACKET_DUAL, PACKET_REAL, false,false> { \
EIGEN_STRONG_INLINE PACKET_DUAL pmadd(const PACKET_DUAL& x, const PACKET_REAL& y, const PACKET_DUAL& c) const \
{ return padd(c, pmul(x,y)); } \
EIGEN_STRONG_INLINE PACKET_DUAL pmul(const PACKET_DUAL& x, const PACKET_REAL& y) const \
{ return PACKET_DUAL(Eigen::internal::pmul<PACKET_REAL>(PACKET_REAL(x.v), y)); } \
};
#if defined EIGEN_VECTORIZE_AVX512
#include "duals/arch/SSE/Dual.h"
#include "duals/arch/AVX/Dual.h"
#include "duals/arch/SSE/ComplexDual.h"
#include "duals/arch/AVX/ComplexDual.h"
#elif defined EIGEN_VECTORIZE_AVX
#include "duals/arch/SSE/Dual.h"
#include "duals/arch/AVX/Dual.h"
#include "duals/arch/SSE/ComplexDual.h"
#include "duals/arch/AVX/ComplexDual.h"
#elif defined EIGEN_VECTORIZE_SSE
#include "duals/arch/SSE/Dual.h"
#include "duals/arch/SSE/ComplexDual.h"
#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX)
// #include "duals/arch/AltiVec/Dual.h" // TODO
#elif defined EIGEN_VECTORIZE_NEON
//#include "duals/arch/NEON/Dual.h" // TODO
#elif defined EIGEN_VECTORIZE_ZVECTOR
// #include "duals/arch/ZVector/Dual.h" // TODO
#endif
#undef EIGEN_MAKE_DCONJ_HELPER_DUAL_REAL
// reallow compiler seppuku
#include "Eigen/src/Core/util/ReenableStupidWarnings.h"
#endif // PARSED_BY_DOXYGEN
//////// gepb for duals::dual
#if 0 // TODO
namespace Eigen { namespace internal {
template<typename RealScalar, bool _ConjLhs>
class gebp_traits<duals::dual<RealScalar>, RealScalar, _ConjLhs, false>
{
public:
typedef duals::dual<RealScalar> LhsScalar;
typedef RealScalar RhsScalar;
typedef typename ScalarBinaryOpTraits<LhsScalar, RhsScalar>::ReturnType ResScalar;
enum {
ConjLhs = _ConjLhs,
ConjRhs = false,
Vectorizable = packet_traits<LhsScalar>::Vectorizable && packet_traits<RhsScalar>::Vectorizable,
LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
ResPacketSize = Vectorizable ? packet_traits<ResScalar>::size : 1,
NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS,
nr = 4,
#if defined(EIGEN_HAS_SINGLE_INSTRUCTION_MADD) && !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX)
// we assume 16 registers
mr = 3*LhsPacketSize,
#else
mr = (EIGEN_PLAIN_ENUM_MIN(16,NumberOfRegisters)/2/nr)*LhsPacketSize,
#endif
LhsProgress = LhsPacketSize,
RhsProgress = 1
};
typedef typename packet_traits<LhsScalar>::type _LhsPacket;
typedef typename packet_traits<RhsScalar>::type _RhsPacket;
typedef typename packet_traits<ResScalar>::type _ResPacket;
typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
typedef ResPacket AccPacket;
EIGEN_STRONG_INLINE void initAcc(AccPacket& p)
{
p = pset1<ResPacket>(ResScalar(0));
}
EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const
{
dest = pset1<RhsPacket>(*b);
}
EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, RhsPacket& dest) const
{
dest = pset1<RhsPacket>(*b);
}
EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
{
dest = pload<LhsPacket>(a);
}
EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacket& dest) const
{
dest = ploadu<LhsPacket>(a);
}
EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3)
{
pbroadcast4(b, b0, b1, b2, b3);
}
// EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1)
// {
// pbroadcast2(b, b0, b1);
// }
EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp) const
{
madd_impl(a, b, c, tmp, typename conditional<Vectorizable,true_type,false_type>::type());
}
EIGEN_STRONG_INLINE void madd_impl(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp, const true_type&) const
{
//std::cerr << CYELLOW "%" << CRESET;
//duals::dual<RealScalar>, RealScalar
// accpacket=lhspacket
#ifdef EIGEN_HAS_SINGLE_INSTRUCTION_MADD
EIGEN_UNUSED_VARIABLE(tmp);
c.v = pmadd(a.v,b,c.v);
#else
tmp = b; tmp = pmul(RhsPacket(a.v),tmp); c = AccPacket(padd(RhsPacket(c.v),tmp));
#endif
}
EIGEN_STRONG_INLINE void madd_impl(const LhsScalar& a, const RhsScalar& b, ResScalar& c, RhsScalar& /*tmp*/, const false_type&) const
{
c += a * b;
}
EIGEN_STRONG_INLINE void acc(const AccPacket& c, const ResPacket& alpha, ResPacket& r) const
{
r = cj.pmadd(c,alpha,r);
}
protected:
dconj_helper<ResPacket,ResPacket,ConjLhs,false> cj;
};
template<typename RealScalar, bool _ConjLhs, bool _ConjRhs>
class gebp_traits<duals::dual<RealScalar>, duals::dual<RealScalar>, _ConjLhs, _ConjRhs >
{
public:
typedef duals::dual<RealScalar> Scalar;
typedef duals::dual<RealScalar> LhsScalar;
typedef duals::dual<RealScalar> RhsScalar;
typedef duals::dual<RealScalar> ResScalar;
enum {
ConjLhs = _ConjLhs,
ConjRhs = _ConjRhs,
Vectorizable = packet_traits<RealScalar>::Vectorizable
&& packet_traits<Scalar>::Vectorizable,
RealPacketSize = Vectorizable ? packet_traits<RealScalar>::size : 1,
ResPacketSize = Vectorizable ? packet_traits<ResScalar>::size : 1,
LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
// FIXME: should depend on NumberOfRegisters
nr = 4,
mr = ResPacketSize,
LhsProgress = ResPacketSize,
RhsProgress = 1
};
typedef typename packet_traits<RealScalar>::type RealPacket;
typedef typename packet_traits<Scalar>::type ScalarPacket;
typedef DoublePacket<RealPacket> DoublePacketType;
typedef typename conditional<Vectorizable,RealPacket, Scalar>::type LhsPacket;
typedef typename conditional<Vectorizable,DoublePacketType,Scalar>::type RhsPacket;
typedef typename conditional<Vectorizable,ScalarPacket,Scalar>::type ResPacket;
typedef typename conditional<Vectorizable,DoublePacketType,Scalar>::type AccPacket;
EIGEN_STRONG_INLINE void initAcc(Scalar& p) { p = Scalar(0); }
EIGEN_STRONG_INLINE void initAcc(DoublePacketType& p)
{
p.first = pset1<RealPacket>(RealScalar(0));
p.second = pset1<RealPacket>(RealScalar(0));
}
// Scalar path
EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, ResPacket& dest) const
{
dest = pset1<ResPacket>(*b);
}
// Vectorized path
EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, DoublePacketType& dest) const
{
dest.first = pset1<RealPacket>(rpart(*b));
dest.second = pset1<RealPacket>(dpart(*b));
}
EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, ResPacket& dest) const
{
loadRhs(b,dest);
}
EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, DoublePacketType& dest) const
{
eigen_internal_assert(unpacket_traits<ScalarPacket>::size<=4);
loadRhs(b,dest);
}
EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3)
{
// FIXME not sure that's the best way to implement it!
loadRhs(b+0, b0);
loadRhs(b+1, b1);
loadRhs(b+2, b2);
loadRhs(b+3, b3);
}
// Vectorized path
EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, DoublePacketType& b0, DoublePacketType& b1)
{
// FIXME not sure that's the best way to implement it!
loadRhs(b+0, b0);
loadRhs(b+1, b1);
}
// Scalar path
EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsScalar& b0, RhsScalar& b1)
{
// FIXME not sure that's the best way to implement it!
loadRhs(b+0, b0);
loadRhs(b+1, b1);
}
// nothing special here
EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
{
dest = pload<LhsPacket>((const typename unpacket_traits<LhsPacket>::type*)(a));
}
EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacket& dest) const
{
dest = ploadu<LhsPacket>((const typename unpacket_traits<LhsPacket>::type*)(a));
}
EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, DoublePacketType& c, RhsPacket& /*tmp*/) const
{
c.first = padd(pmul(a,b.first), c.first);
c.second = padd(pmul(a,b.second),c.second);
}
EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, ResPacket& c, RhsPacket& /*tmp*/) const
{
c = cj.pmadd(a,b,c);
}
EIGEN_STRONG_INLINE void acc(const Scalar& c, const Scalar& alpha, Scalar& r) const { r += alpha * c; }
EIGEN_STRONG_INLINE void acc(const DoublePacketType& c, const ResPacket& alpha, ResPacket& r) const
{
// assemble c
ResPacket tmp;
if((!ConjLhs)&&(!ConjRhs))
{
tmp = pcplxflip(pconj(ResPacket(c.second)));
tmp = padd(ResPacket(c.first),tmp);
}
else if((!ConjLhs)&&(ConjRhs))
{
tmp = pconj(pcplxflip(ResPacket(c.second)));
tmp = padd(ResPacket(c.first),tmp);
}
else if((ConjLhs)&&(!ConjRhs))
{
tmp = pcplxflip(ResPacket(c.second));
tmp = padd(pconj(ResPacket(c.first)),tmp);
}
else if((ConjLhs)&&(ConjRhs))
{
tmp = pcplxflip(ResPacket(c.second));
tmp = psub(pconj(ResPacket(c.first)),tmp);
}
r = pmadd(tmp,alpha,r);
}
protected:
dconj_helper<LhsScalar,RhsScalar,ConjLhs,ConjRhs> cj;
};
template<typename RealScalar, bool _ConjRhs>
class gebp_traits<RealScalar, duals::dual<RealScalar>, false, _ConjRhs >
{
public:
typedef duals::dual<RealScalar> Scalar;
typedef RealScalar LhsScalar;
typedef Scalar RhsScalar;
typedef Scalar ResScalar;
enum {
ConjLhs = false,
ConjRhs = _ConjRhs,
Vectorizable = packet_traits<RealScalar>::Vectorizable
&& packet_traits<Scalar>::Vectorizable,
LhsPacketSize = Vectorizable ? packet_traits<LhsScalar>::size : 1,
RhsPacketSize = Vectorizable ? packet_traits<RhsScalar>::size : 1,
ResPacketSize = Vectorizable ? packet_traits<ResScalar>::size : 1,
NumberOfRegisters = EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS,
// FIXME: should depend on NumberOfRegisters
nr = 4,
mr = (EIGEN_PLAIN_ENUM_MIN(16,NumberOfRegisters)/2/nr)*ResPacketSize,
LhsProgress = ResPacketSize,
RhsProgress = 1
};
typedef typename packet_traits<LhsScalar>::type _LhsPacket;
typedef typename packet_traits<RhsScalar>::type _RhsPacket;
typedef typename packet_traits<ResScalar>::type _ResPacket;
typedef typename conditional<Vectorizable,_LhsPacket,LhsScalar>::type LhsPacket;
typedef typename conditional<Vectorizable,_RhsPacket,RhsScalar>::type RhsPacket;
typedef typename conditional<Vectorizable,_ResPacket,ResScalar>::type ResPacket;
typedef ResPacket AccPacket;
EIGEN_STRONG_INLINE void initAcc(AccPacket& p)
{
p = pset1<ResPacket>(ResScalar(0));
}
EIGEN_STRONG_INLINE void loadRhs(const RhsScalar* b, RhsPacket& dest) const
{
dest = pset1<RhsPacket>(*b);
}
void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1, RhsPacket& b2, RhsPacket& b3)
{
pbroadcast4(b, b0, b1, b2, b3);
}
// EIGEN_STRONG_INLINE void broadcastRhs(const RhsScalar* b, RhsPacket& b0, RhsPacket& b1)
// {
// // FIXME not sure that's the best way to implement it!
// b0 = pload1<RhsPacket>(b+0);
// b1 = pload1<RhsPacket>(b+1);
// }
EIGEN_STRONG_INLINE void loadLhs(const LhsScalar* a, LhsPacket& dest) const
{
dest = ploaddup<LhsPacket>(a);
}
EIGEN_STRONG_INLINE void loadRhsQuad(const RhsScalar* b, RhsPacket& dest) const
{
eigen_internal_assert(unpacket_traits<RhsPacket>::size<=4);
loadRhs(b,dest);
}
EIGEN_STRONG_INLINE void loadLhsUnaligned(const LhsScalar* a, LhsPacket& dest) const
{
dest = ploaddup<LhsPacket>(a);
}
EIGEN_STRONG_INLINE void madd(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp) const
{
madd_impl(a, b, c, tmp, typename conditional<Vectorizable,true_type,false_type>::type());
}
EIGEN_STRONG_INLINE void madd_impl(const LhsPacket& a, const RhsPacket& b, AccPacket& c, RhsPacket& tmp, const true_type&) const
{
//std::cerr << CYELLOW "*" << CRESET;
//RealScalar, duals::dual<RealScalar>
#ifdef EIGEN_HAS_SINGLE_INSTRUCTION_MADD
EIGEN_UNUSED_VARIABLE(tmp);
c.v = pmadd(a,b.v,c.v);
#else
tmp = b; tmp = RhsPacket(pmul(a,LhsPacket(tmp.v))); c = padd(c,tmp);
#endif
}
EIGEN_STRONG_INLINE void madd_impl(const LhsScalar& a, const RhsScalar& b, ResScalar& c, RhsScalar& /*tmp*/, const false_type&) const
{
c += a * b;
}
EIGEN_STRONG_INLINE void acc(const AccPacket& c, const ResPacket& alpha, ResPacket& r) const
{
r = cj.pmadd(alpha,c,r);
}
protected:
dconj_helper<ResPacket,ResPacket,false,ConjRhs> cj;
};
} } // Eigen::internal
#endif // gebp_traits
////////
#endif // CPPDUALS_DONT_VECTORIZE
#endif // CPPDUALS_DUAL_EIGEN

BIN
src/include/cppduals/paper/benchmark.png

After

Width: 610  |  Height: 219  |  Size: 15 KiB

86
src/include/cppduals/paper/paper.bib

@ -0,0 +1,86 @@
%
% biber --tool --output_align --output_indent=2 --output_fieldcase=lower paper.bib
%
@misc{eigenweb,
author = {Guennebaud, Gaël and Jacob, Benoît and others},
date = {2010},
howpublished = {\url{http://eigen.tuxfamily.org}},
title = {Eigen v3},
}
@misc{autodiff,
author = {Leal, Allan},
date = {2019},
howpublished = {\url{https://github.com/autodiff/autodiff}},
title = {Autodiff},
}
@misc{autodifforg,
author = {Bücker, Martin and Hovland, Paul},
date = {2019},
howpublished = {\url{http://www.autodiff.org}},
title = {autodiff.org},
}
@misc{spindrops,
author = {Tesch, Michael and Glaser, Niklas and Glaser, Steffen J.},
date = {2019},
howpublished = {\url{https://spindrops.org/}},
title = {SpinDrops 2.0},
}
@inproceedings{openblas,
address = {Denver, Colorado},
author = {Wang, Qian and Zhang, Xianyi and Zhang, Yunquan and Yi, Qing},
booktitle = {Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis ({SC13})},
doi = {10.1145/2503210.2503219},
isbn = {978-1-4503-2378-9},
language = {en},
pages = {1-12},
publisher = {{ACM Press}},
title = {{AUGEM}: Automatically Generate High Performance Dense Linear Algebra Kernels on {X86 CPUs}},
year = {2013}
}
@incollection{FAD,
abstract = {This work deals with an implementation of automatic differentiation of C++ computer programs in forward mode using operator overloading and expression templates. In conjunction with a careful reuse of data, this technique also improves performance of programs involving linear algebra computations mixed or not with automatic differentiation. We give a broad view of implementation and explain some important concepts regarding code optimization. We conclude with some benchmarks applied to our optimal control software.},
author = {Aubert, Pierre and Di C{é}sar{é}, Nicolas},
editor = {Corliss, George and Faure, Christ{è}le and Griewank, Andreas and Hasco{ë}t, Laurent and Naumann, Uwe},
location = {New York, NY},
publisher = {Springer},
booktitle = {Automatic Differentiation of Algorithms: From Simulation to Optimization},
chapter = {37},
crossref = {Corliss2002ADo},
doi = {10.1007/978-1-4613-0075-5},
date = {2002},
pages = {311--315},
series = {Computer and Information Science},
title = {Expression Templates and Forward Mode Automatic Differentiation},
}
@misc{audi,
abstract = {Header only, C++ library (and the Python pyaudi package) implementing the algebra of Taylor truncated polynomials and a few algorithms useful for its applications (Differential Intelligence, automatic differentiation, Taylor Models, etc.)},
author = {Izzo, Dario and Biscani, Francesco and Sánchez, Carlos and Müller, Jörg and Heddes, Mike},
date = {2019-05},
doi = {10.5281/zenodo.2677671},
howpublished = {Zenodo},
shorttitle = {Darioizzo/Audi},
title = {Darioizzo/Audi: {{Update}} Third Party Dependencies},
}
@inproceedings{adolc,
author = {Walther, Andrea},
booktitle = {Combinatorial Scientific Computing},
editor = {Uwe Naumann and Olaf Schenk},
publisher = {Chapman-Hall CRC Computational Science},
year = {2012},
title = {Getting started with {ADOL-C}},
isbn = {9781439827352},
}
@misc{ceres,
author = {Agarwal, Sameer and Mierle, Keir and others},
howpublished = {\url{http://ceres-solver.org}},
title = {Ceres Solver},
}

164
src/include/cppduals/paper/paper.md

@ -0,0 +1,164 @@
---
title: 'cppduals: a nestable vectorized templated dual number library for C++11'
tags:
- C++
- dual numbers
- autodiff
- differentiation
- vectorization
- Eigen
authors:
- name: Michael Tesch
orcid: 0000-0003-4096-1562
affiliation: "1"
affiliations:
- name: Department of Chemistry, Technische Universität München, 85747 Garching, Germany
index: 1
date: 09 May 2019
bibliography: paper.bib
---
# Summary
Mathematical algorithms in the field of optimization often require the
simultaneous computation of a function and its derivative. The
derivative of many functions can be found automatically, a process
referred to as automatic differentiation. Dual numbers, close
relatives of the complex numbers, are of particular use in automatic
differentiation. This library provides an extremely fast
implementation of dual numbers for C++, ``duals::dual<>``, which, when
replacing scalar types, can be used to automatically calculate a
derivative.
A real function's value can be made to carry the derivative of the
function with respect to a real argument by replacing the real
argument with a dual number having a unit dual part. This property is
recursive: replacing the real part of a dual number with more dual
numbers results in the dual part's dual part holding the function's
second derivative. The ``dual<>`` type in this library allows this
nesting (although we note here that it may not be the fastest solution
for calculating higher order derivatives.)
There are a large number of automatic differentiation libraries and
classes for C++: adolc [@adolc], FAD [@FAD], autodiff [@autodiff],
ceres [@ceres], AuDi [@audi], to name a few, with another 30-some
listed at [autodiff.org @autodifforg]. But there were no simple
single-file stand-alone header libraries that were explicitly
vectorized. *Cppduals* can be copied and used as a single header file
``duals/dual`` with no dependencies other than the standard library,
and the vectorization support is contained in a small number of
additional auxiliary files. The interface generally follows the
conventions of the C++11 standard library's ``std::complex`` type, and
has very liberal licensing.
In order to fully utilize the computing resources of modern CPUs it is
often necessary to use their special data-parallel capabilities.
However, compilers often struggle to find the best sequence of
instructions to achieve maximum performance due to difficulties in
automatically detecting parallel data operations in programs and then
mapping those parallel operations onto the CPU's data-parallel
instructions. Some intervention from the programmer to exploit these
special data-parallel instructions, combined with cache-optimized
algorithms, can improve program execution speed significantly. This
is done by *cppduals* through providing template specializations for
selected C++ data types.
Template specializations that map the dual arithmetic directly to
vector machine language are provided for the types typically used to
calculate first-order derivatives: ``dual<float>``, ``dual<double>``,
``std::complex<dual<float>>``, and ``std::complex<dual<double>>``.
These types and their algebras are expressed in hand-coded assembly
for use with the Eigen [@eigenweb] matrix library. The vector
operations for the ``dual<>`` type are then picked up automatically by
Eigen's cache-optimized algorithms. The integration lets us achieve
extremely fast performance for automatic forward, first-order
differentiation of matrix expressions. Furthermore, by piggy-backing
on Eigen's algorithms, the library inherits future improvements and
adaptations to other hardware platforms. The vector specializations
are currently available for the x86_64 SSE and AVX instruction sets,
though support for other vector machine architectures (such as GPUs)
can easily be added.
# Mathematics
A dual number has a *real part* and a *dual part*, the *dual part* is
multiplied by the dual unit $\epsilon$, with the property that
$\epsilon^2 = 0$. Formally the dual space, $\mathbb{D} = \{ x = a + b
\epsilon \; | \; a, b \in \mathbb{R}, \epsilon^2 = 0 \}$.
The property can be used to differentiate functions of real values by
expanding $f(x)$ as its Taylor series at $a$:
$$f(x) = f(a) + f'(a)(x-a) + \frac{f''(a)}{2!}(x-a)^2 + \frac{f'''(a)}{3!}(x-a)^3 + ... $$
Setting $x = a + b\epsilon$ in this expansion gives
$$\begin{split}
f(a + b \epsilon) &= f(a) + f'(a)(b \epsilon) + \frac{f''(a)}{2!}(b \epsilon)^2
+ \frac{f'''(a)}{3!}(b \epsilon)^3 + ...\\
&= f(a) + f'(a)(b \epsilon)
\end{split}$$
Because the $\epsilon^2$ terms are zero, the Taylor expansion
truncates after the $f'$ term. Thus to evaluate $f'(a)$: set $x = a +
b\epsilon$ with $b=1$, and take the dual part of the evaluated
function $\mathfrak{Du}(f(x))$.
A matrix representation of the dual numbers is $\bigl(
\begin{smallmatrix}a & b \\ 0 & a\end{smallmatrix}\bigr)$. This form
can be used to calculate Fréchet derivatives of matrix functions $D_B
f(\mathbf{A})$ by doubling the size of the calculation and embedding
the parameter ($A$) and with-regard-to parts ($B$) into this doubled
matrix, zeroing the lower left quadrant: $D_B f(\mathbf{A}) = C$ where
$f\bigl( \begin{smallmatrix}A & B \\ 0 & A\end{smallmatrix}\bigr) =
\bigl( \begin{smallmatrix}F & C \\ 0 & F\end{smallmatrix}\bigr)$.
# Benchmarks
The above blocking method of computing matrix function derivatives
requires twice as much memory as using dual numbers, and furthermore
does not take advantage of the relative sparsity of dual number
arithmetic. However, the blocking method *does* permit the use of
highly optimized complex-valued BLAS libraries, which are often
significantly faster than "regularly" compiled code, being hand-tuned
for a specific CPU architecture and memory heirarchy. We compared
using ``dual<>`` to calculate the derivative of the matrix-matrix
product with using the blocking method implemented with OpenBLAS
[@openblas]. All benchmarks were performed single-threaded on an
*Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz* running *Fedora 30*, using
*Eigen v3.3.7*, *OpenBLAS v0.3.6*, and compiled using *clang v8.0.0*.
The *cppduals* vectorized type reduced the time of a 32x32
matrix-multiplication derivative by 40% over the 2Nx2N (in this case
64x64) multiplication performed by OpenBLAS (even with a suspected
performance bug in Eigen's GEMM algorithm, described below). In the
current implementation, this advantage diminishes as the matrix size
grows, as shown in Figure 1 ![Figure 1.](benchmark.png), we suspect
this is due to a bug in Eigen's cache optimization for non-scalar
valued matrix-matrix multiplication. We note that the Eigen
scalar-valued matrix multiplications are roughly as fast as OpenBLAS,
demonstrating the validity of Eigen's approach to optimization, but
complex-valued multiplications take roughly twice as much time as
their OpenBLAS equivalents, indicating a performance bug in Eigen's
current optimizations, though only for complex-valued (and
consequently, dual-valued) matrices.
We hope to achieve further speed improvements with tuning and more
debugging of the integration with Eigen. In general, dual-valued
operations should be marginally faster than corresponding
complex-valued operations, as they require slightly fewer floating
point operations.
# Usage
*Cppduals* is used in the SpinDrops [@spindrops] NMR and quantum
computing software for optimization of pulse quality functions.
# Acknowledgments
We acknowledge first of all the Eigen project and its contributors,
upon which the vectorization was based. Some funding was provided by
the TUM School of Education.
# References

240
src/include/cppduals/tests/CMakeLists.txt

@ -0,0 +1,240 @@
#
# Part of the cppduals Project
#
# (c)2019 Michael Tesch. tesch1@gmail.com
#
# See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
# license information.
#
# This Source Code Form is subject to the terms of the Mozilla
# Public License v. 2.0. If a copy of the MPL was not distributed
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
# gtest_discover_tests requires 3.10
cmake_minimum_required (VERSION 3.10)
# Configure google-test as a downloadable library.
include (GoogleTest)
if (WIN32)
add_definitions (-D_USE_MATH_DEFINES)
endif ()
include_directories ("${CMAKE_SOURCE_DIR}")
include_directories ("${DEPS_ROOT}/include")
include_directories ("${EIGEN3_INCLUDE_DIRS}")
#include_directories ("${MPFR_INCLUDES}")
include_directories ("${EXPOKIT_INCLUDE_DIR}")
set (IOFORMAT "IOFormat(FullPrecision, DontAlignCols, \", \", \"\\$<SEMICOLON>\\n\", \"\", \"\", \"[\", \"]\")")
add_definitions (-DEIGEN_DEFAULT_IO_FORMAT=${IOFORMAT})
#add_definitions (-DEIGEN_DEFAULT_IO_FORMAT=EIGEN_IO_FORMAT_OCTAVE)
#
# Correctness & Coverage
#
if (NOT MSVC)
set (OPT_FLAGS "-O2")
set (OPT_FLAGS "-O3;-msse3")
set (OPT_FLAGS "-O3;-mavx2;-mfma")
set (OPT_FLAGS "-O3;-march=native")
else ()
set (OPT_FLAGS "/arch:IA32")
set (OPT_FLAGS "/arch:SSE")
set (OPT_FLAGS "/arch:SSE2")
set (OPT_FLAGS "/arch:AVX2")
endif ()
#set (OPT_FLAGS "${OPT_FLAGS};-fsanitize=address;-fno-omit-frame-pointer")
set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_VECTORIZE_CDUAL")
#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
#set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE")
set (ALL_TESTS
test_dual test_funcs test_eigen test_packets
test_vectorize test_solve test_expm test_1 test_fmt
example
)
set (ALL_TEST_BINS )
foreach (TEST_ ${ALL_TESTS})
foreach (PHASE 1 2 3 4 5)
# check if file has phase defined
file (READ ${TEST_}.cpp TMPTXT)
string (FIND "${TMPTXT}" "PHASE_${PHASE}" hasphase)
if ((${hasphase} EQUAL -1) AND NOT (${PHASE} EQUAL 1))
continue ()
endif ()
set (TEST ${TEST_}_${PHASE})
message ("Adding test ${TEST}")
set (ALL_TEST_BINS ${ALL_TEST_BINS} ${TEST})
add_executable (${TEST} ${TEST_}.cpp)
set (PHASE_FLAGS ${OPT_FLAGS} -DPHASE_${PHASE})
string (REPLACE ";" ", " L2 "${CMAKE_CXX_FLAGS}")
target_compile_options (${TEST} PUBLIC ${PHASE_FLAGS})
target_compile_definitions (${TEST} PRIVATE "OPT_FLAGS=${L2}")
target_link_libraries (${TEST} gtest_main cppduals_coverage_config)
#target_link_libraries (${TEST} -lasan)
add_dependencies (${TEST} eigenX expokitX)
gtest_discover_tests (${TEST} TEST_LIST ${TEST}_targets)
set_tests_properties (${${TEST}_targets} PROPERTIES TIMEOUT 10)
# -ftest-coverage
endforeach (PHASE)
endforeach (TEST_)
# special for fmt
target_compile_features (test_fmt_1 PUBLIC cxx_std_14)
target_link_libraries (test_fmt_1 fmt::fmt)
if (CPPDUALS_BENCHMARK)
#
# Benchmarks
#
message ("searching: ${DEPS_ROOT} for google benchmark libs")
find_library (BENCHMARK_LIBRARY benchmark PATHS ${DEPS_ROOT}/lib)
find_library (BENCHMARKM_LIBRARY benchmark_main PATHS ${DEPS_ROOT}/lib)
#find_library (PTHREAD_LIBRARY pthread)
message ("BENCHMARK_LIBRARY: ${BENCHMARK_LIBRARY}")
include_directories ("${BENCHMARK_INC_DIR}")
if (Boost_FOUND AND NO)
add_definitions (-DHAVE_BOOST=1)
include_directories ("${Boost_INCLUDE_DIRS}")
include_directories ("${PIRANHA_INCLUDE_DIR}")
include_directories ("${AUDI_INCLUDE_DIR}")
endif (Boost_FOUND AND NO)
if (NOT APPLE AND NOT BLA_VENDOR)
if (NOT BLA_STATIC)
# default to static
set (BLA_STATIC OFF)
endif (NOT BLA_STATIC)
set (BLA_VENDOR OpenBLAS)
endif (NOT APPLE AND NOT BLA_VENDOR)
find_package (BLAS REQUIRED)
#find_package (LAPACK REQUIRED)
add_definitions (-DHAVE_BLAS)
#add_definitions (-DEIGEN_USE_BLAS)
# find lapacke.h cblas.h
set (CBLAS_HINTS ${BLAS_DIR} ${LAPACK_DIR} /usr /usr/local /opt /opt/local)
set (CBLAS_PATHS
/usr
/usr/local
/opt
/opt/local
/usr/local/opt
/System/Library/Frameworks)
# Finds the include directories for lapacke.h
find_path (LAPACKE_INCLUDE_DIRS
NAMES lapacke.h
HINTS ${CBLAS_HINTS}
PATH_SUFFIXES
include inc include/x86_64 include/x64
openblas/include
# Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers
PATHS ${CBLAS_PATHS}
DOC "LAPACK(E) include header lapacke.h")
mark_as_advanced (LAPACKE_INCLUDE_DIRS)
if (LAPACKE_INCLUDE_DIRS)
include_directories (${LAPACKE_INCLUDE_DIRS})
else ()
add_definitions (-DEIGEN_LAPACKE)
endif (LAPACKE_INCLUDE_DIRS)
# Finds the include directories for cblas*.h
find_path (CBLAS_INCLUDE_DIRS
NAMES cblas.h cblas_openblas.h cblas-openblas.h
HINTS ${CBLAS_HINTS}
PATH_SUFFIXES
include inc include/x86_64 include/x64
openblas/include
# Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers
PATHS ${CBLAS_PATHS}
DOC "BLAS include header cblas.h")
mark_as_advanced (CBLAS_INCLUDE_DIRS)
include_directories (${CBLAS_INCLUDE_DIRS})
foreach (cblas in cblas.h cblas_openblas.h cblas-openblas.h)
if (EXISTS "${CBLAS_INCLUDE_DIRS}/${cblas}")
add_definitions (-DCBLAS_HEADER="${cblas}")
break()
endif (EXISTS "${CBLAS_INCLUDE_DIRS}/${cblas}")
endforeach (cblas)
message ("Found BLAS : ${BLAS_LIBRARIES}")
message ("Found cBLAS : ${CBLAS_INCLUDE_DIRS}")
message ("Found lapacke : ${LAPACKE_INCLUDE_DIRS}")
set (OPT_FLAGS "")
if (NOT MSVC)
#set (OPT_FLAGS "-O3;-mavx")
#set (OPT_FLAGS "-O3;-march=native;-fopenmp")
set (OPT_FLAGS "-O3;-msse3;-fopenmp")
set (OPT_FLAGS "-O3")
set (OPT_FLAGS "-O3;-msse3")
set (OPT_FLAGS "-O3;-march=native;-funroll-loops")
set (OPT_FLAGS "-O3;-msse3;-mavx2;-mfma")
set (OPT_FLAGS "-O3;-march=native")
#set (OPT_FLAGS "${OPT_FLAGS};-save-temps;-fverbose-asm")
else ()
set (OPT_FLAGS "/arch:IA32")
set (OPT_FLAGS "/arch:SSE")
set (OPT_FLAGS "/arch:SSE2")
set (OPT_FLAGS "/arch:AVX2")
endif ()
#set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE")
#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL")
foreach (BENCH bench_dual bench_eigen bench_gemm bench_example bench_fmt)
add_executable (${BENCH} ${BENCH}.cpp)
target_compile_options (${BENCH} PUBLIC ${OPT_FLAGS})
#set_target_properties (${BENCH} PROPERTIES LINK_FLAGS -fopenmp)
#target_link_options (${BENCH} PUBLIC ${OPT_FLAGS})
string (REPLACE ";" ", " L2 "${OPT_FLAGS} ${CMAKE_CXX_FLAGS}")
target_compile_definitions (${BENCH} PRIVATE "OPT_FLAGS=${L2}")
add_dependencies (${BENCH} benchmarkX eigenX expokitX)
target_link_libraries (${BENCH} ${BENCHMARK_LIBRARY} -lpthread ${BLAS_LIBRARIES})
endforeach (BENCH)
target_link_libraries (bench_fmt fmt::fmt)
endif (CPPDUALS_BENCHMARK)
add_executable (sandbox sandbox.cpp)
add_dependencies (sandbox eigenX expokitX ) # mpfrX mprealX
#target_compile_options (sandbox PUBLIC ${OPT_FLAGS})
target_compile_options (sandbox PUBLIC -DCPPDUALS_VECTORIZE_CDUAL)
if (MSVC)
target_compile_options (sandbox PUBLIC /arch:AVX2)
else ()
target_compile_options (sandbox PUBLIC -O1 -msse3 -mavx2 -mfma)
endif ()
set_target_properties (sandbox PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries (sandbox PUBLIC cppduals_coverage_config)
#
# Generate coverage reports
#
if (CODE_COVERAGE)
add_custom_target (cov
DEPENDS ${ALL_TEST_BINS}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test
COMMAND $<TARGET_FILE:sandbox>
COMMAND lcov --capture --directory . --output-file coverage.info
COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info
COMMAND lcov --remove coverage.info '*/thirdparty/*' --output-file coverage.info
COMMAND lcov --remove coverage.info '*/googletest/*' --output-file coverage.info
COMMAND lcov --list coverage.info
)
add_custom_target (cov-html
DEPENDS cov
COMMAND rm -rf ../coverage
COMMAND genhtml --ignore-errors source coverage.info --legend --title "make cov"
--output-directory=../coverage
COMMAND echo "output in coverage/index.html"
)
endif ()

88
src/include/cppduals/tests/bench_dual.cpp

@ -0,0 +1,88 @@
//===-- bench_dual - test dual class ----------------------------*- C++ -*-===//
//
// Part of the cppduals Project
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
#include <iostream>
#include "benchmark/benchmark.h"
#include "type_name.hpp"
#include <Eigen/Core> // for SimdInstructionSetsInUse()
#include <duals/dual>
#define N_RANGE ->RangeMultiplier(8)->Range(2, 1<<13) // 2 - 2048
template <class Rt> void B_Add(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> c(N);
for (auto _ : state) {
for (int i = 0; i < N; i++)
a[i] = b[i] + c[i];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
}
template <class Rt> void B_Sub(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> c(N);
for (auto _ : state) {
for (int i = 0; i < N; i++)
a[i] = b[i] - c[i];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
}
template <class Rt> void B_Mul(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> c(N);
for (auto _ : state) {
for (int i = 0; i < N; i++)
a[i] = b[i] * c[i];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
}
template <class Rt> void B_Div(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> c(N);
for (auto _ : state) {
for (int i = 0; i < N; i++)
a[i] = b[i] / c[i];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
}
BENCHMARK_TEMPLATE(B_Add, duals::dualf) N_RANGE;
BENCHMARK_TEMPLATE(B_Add, std::complex<float>) N_RANGE;
//BENCHMARK_TEMPLATE(B_Add, std::complex<duals::dualf>) N_RANGE;
BENCHMARK_TEMPLATE(B_Sub, duals::dualf) N_RANGE;
BENCHMARK_TEMPLATE(B_Sub, std::complex<float>) N_RANGE;
BENCHMARK_TEMPLATE(B_Mul, duals::dualf) N_RANGE;
BENCHMARK_TEMPLATE(B_Mul, std::complex<float>) N_RANGE;
BENCHMARK_TEMPLATE(B_Div, duals::dualf) N_RANGE;
BENCHMARK_TEMPLATE(B_Div, std::complex<float>) N_RANGE;
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char** argv)
{
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}

398
src/include/cppduals/tests/bench_eigen.cpp

@ -0,0 +1,398 @@
//===-- bench_dual - test dual class ----------------------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
#include <iostream>
#include <fstream>
#include <complex>
#include <memory>
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Core>
#include <Eigen/Dense>
#include "eexpokit/padm.hpp"
#include "eexpokit/chbv.hpp"
#include "eexpokit/expv.hpp"
//#include "eexpokit/mexpv.hpp"
#include "benchmark/benchmark.h"
using namespace duals;
template< class T > struct type_identity { typedef T type; };
namespace Eigen {
namespace internal {
template<typename T> struct is_exp_known_type;
template<typename T> struct is_exp_known_type<std::complex<T>> : is_exp_known_type<T> {};
#if 0
template <typename RealScalar> struct MatrixExponentialScalingOp;
template <typename RealScalar>
struct MatrixExponentialScalingOp<duals::dual<RealScalar>>
{
MatrixExponentialScalingOp(int squarings) : m_squarings(squarings) { }
inline const duals::dual<RealScalar> operator() (const duals::dual<RealScalar> & x) const
{
using std::ldexp;
return ldexp(x, -m_squarings);
}
typedef std::complex<duals::dual<RealScalar>> ComplexScalar;
inline const ComplexScalar operator() (const ComplexScalar& x) const
{
using std::ldexp;
return ComplexScalar(ldexp(x.real(), -m_squarings), ldexp(x.imag(), -m_squarings));
}
private:
int m_squarings;
};
#endif
}}
#include <unsupported/Eigen/MatrixFunctions>
namespace Eigen {
namespace internal {
template <typename MatrixType, typename T>
struct matrix_exp_computeUV<MatrixType, duals::dual<T> >
{
typedef typename NumTraits<typename traits<MatrixType>::Scalar>::Real RealScalar;
template <typename ArgType>
static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings)
{
using std::frexp;
using std::pow;
const RealScalar l1norm = arg.cwiseAbs().colwise().sum().maxCoeff();
squarings = 0;
if (l1norm < 1.495585217958292e-002) {
matrix_exp_pade3(arg, U, V);
} else if (l1norm < 2.539398330063230e-001) {
matrix_exp_pade5(arg, U, V);
} else if (l1norm < 9.504178996162932e-001) {
matrix_exp_pade7(arg, U, V);
} else if (l1norm < 2.097847961257068e+000) {
matrix_exp_pade9(arg, U, V);
} else {
const RealScalar maxnorm = 5.371920351148152;
frexp(l1norm / maxnorm, &squarings);
if (squarings < 0) squarings = 0;
MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<RealScalar>(squarings));
matrix_exp_pade13(A, U, V);
}
}
};
}}
/* encode the type into an integer for benchmark output */
template<typename Tp> struct type_num { /* should fail */ };
template<> struct type_num<float> { static constexpr int id = 1; };
template<> struct type_num<double> { static constexpr int id = 2; };
template<> struct type_num<long double> { static constexpr int id = 3; };
template<typename Tp> struct type_num<std::complex<Tp>> { static constexpr int id = 10 + type_num<Tp>::id; };
template<typename Tp> struct type_num<duals::dual<Tp>> { static constexpr int id = 100 + type_num<Tp>::id; };
using duals::dualf;
using duals::duald;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class T> using MatrixX = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
#if 0
#define V_RANGE(V,NF) ->Arg(V*4/NF)->Arg(V*32/NF)->Arg(V*256/NF)->Arg(V*2048/NF)->Arg(V*1)->Complexity()
#else
#define V_RANGE(V,NF) ->Arg(V*1024/NF)
#endif
template <class Rt, class U> void B_VecVecAddCXX(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> c(N);
for (auto _ : state) {
for (int i = 0; i < N; i++)
a[i] = b[i] + b[i];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure Eigen's vec-vec multiplication
template <class Rt, class U> void B_VecVecAdd(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> B = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> C = MatrixX<Rt>::Random(N, 1);
for (auto _ : state) {
B = A + A;
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure Eigen's vec-vec multiplication
template <class Rt, class U> void B_VecVecSub(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> B = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> C = MatrixX<Rt>::Random(N, 1);
for (auto _ : state) {
B = A - A;
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt, class U> void B_VecVecMulCXX(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> c(N);
for (auto _ : state) {
for (int i = 0; i < N; i++)
b[i] = a[i] * a[i];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure Eigen's vec-vec multiplication
template <class Rt, class U> void B_VecVecMul(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> B = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> C = MatrixX<Rt>::Random(N, 1);
for (auto _ : state) {
B = A.array() * C.array();
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure Eigen's vec-vec multiplication
template <class Rt, class U> void B_VecVecDiv(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> B = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> C = MatrixX<Rt>::Random(N, 1);
for (auto _ : state) {
C = A.array() / B.array();
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure Eigen's matrix-matrix multiplication
template <class T, class U> void B_MatMat(benchmark::State& state) {
int N = state.range(0);
typedef typename Eigen::ScalarBinaryOpTraits<T, U>::ReturnType R;
MatrixX<T> A = MatrixX<T>::Random(N, N);
MatrixX<U> B = MatrixX<U>::Random(N, N);
MatrixX<R> C = MatrixX<R>::Random(N, N);
for (auto _ : state) {
C.noalias() = A * B;
benchmark::ClobberMemory(); // Force c to be written to memory.
}
state.counters["type"] = type_num<T>::id;
state.SetComplexityN(state.range(0));
}
// measure compiler's matrix-matrix multiplication
template <class Rt, class U> void B_MatMatCXX(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N*N);
std::vector<Rt> b(N*N);
std::vector<Rt> c(N*N);
for (auto _ : state) {
state.PauseTiming();
a.assign(N*N,1.1);
b.assign(N*N,2.2);
c.assign(N*N,0.);
state.ResumeTiming();
for(int i=0; i<N; ++i)
for(int j=0; j<N; ++j)
for(int k=0; k<N; ++k)
c[i*N+j] += a[i*N+k] * b[k*N+j];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure Eigen's matrix-matrix solve
template <class Rt, class U> void B_MatDiv(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> B = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> C = MatrixX<Rt>::Zero(N, N);
for (auto _ : state) {
C = B.partialPivLu().solve(A); // C = A / B
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
// measure eigen's matrix-vector multiplication
template <class Rt, class U> void B_MatVec(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> b = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> c = MatrixX<Rt>::Random(N, 1);
for (auto _ : state) {
c = A * b;
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_Expm(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> B = MatrixX<Rt>::Zero(N, N);
//A = S * A / A.norm();
for (auto _ : state) {
B = A.exp();
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_ExpPadm(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> B = MatrixX<Rt>::Zero(N, N);
//A = S * A / A.norm();
for (auto _ : state) {
B = eexpokit::padm(A);
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_ExpExpv(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Zero(N, N);
MatrixX<Rt> b = MatrixX<Rt>::Ones(N, 1);
MatrixX<Rt> c = MatrixX<Rt>::Zero(N, 1);
//A = S * A / A.norm();
// sparse random fill
for (int i = 0; i < 4*N; i++)
A((int)duals::randos::random(0.,N-1.),
(int)duals::randos::random(0.,N-1.)) = duals::randos::random2<Rt>();
for (auto _ : state) {
auto ret = eexpokit::expv(1,A,b);
if (ret.err > 1) {
std::ofstream f("fail.m");
f << "A=" << A.format(eexpokit::OctaveFmt) << "\n";
break;
}
// c = ret.w
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_ExpChbv(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> b = MatrixX<Rt>::Zero(N, 1);
MatrixX<Rt> c = MatrixX<Rt>::Zero(N, 1);
//A = S * A / A.norm();
for (auto _ : state) {
c = eexpokit::chbv(A,b);
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
#define MAKE_BM_SIMPLE(TYPE1,TYPE2,NF) \
BENCHMARK_TEMPLATE(B_VecVecAdd, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_VecVecSub, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_VecVecMul, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_VecVecDiv, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_MatVec, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_MatMat, TYPE1,TYPE2) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_MatDiv, TYPE1,TYPE2) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_Expm, TYPE1) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_ExpPadm, TYPE1) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_ExpChbv, TYPE1) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_ExpExpv, TYPE1) V_RANGE(1,NF)
#define MAKE_BENCHMARKS(TYPE1,TYPE2,NF) \
MAKE_BM_SIMPLE(TYPE1,TYPE2,NF)
// BENCHMARK_TEMPLATE(B_VecVecMulCXX, TYPE1,TYPE2) V_RANGE(4,NF);
// BENCHMARK_TEMPLATE(B_MatMatCXX, TYPE1,TYPE2) V_RANGE(1,NF);
#if 1
MAKE_BENCHMARKS(float, float, 1);
MAKE_BENCHMARKS(complexf, complexf,2);
MAKE_BM_SIMPLE(dualf, dualf,2);
MAKE_BM_SIMPLE(cdualf, cdualf,4);
#else
MAKE_BENCHMARKS(double, double,1);
MAKE_BENCHMARKS(complexd, complexd,2);
MAKE_BM_SIMPLE(duald, duald,2);
MAKE_BM_SIMPLE(cduald, cduald,4);
#endif
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char** argv)
{
#ifndef EIGEN_VECTORIZE
static_assert(false, "no vectorization?");
#endif
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}

74
src/include/cppduals/tests/bench_example.cpp

@ -0,0 +1,74 @@
//===-- bench_example - benchmark the examples ---------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
#include <complex>
#include <duals/dual>
#include "benchmark/benchmark.h"
using namespace duals;
template <class T> T f(T x) { return pow(x,pow(x,x)); }
template <class T> T df(T x) { return pow(x,-1. + x + pow(x,x)) * (1. + x*log(x) + x*pow(log(x),2.)); }
template <class T> T ddf(T x) { return (pow(x,pow(x,x)) * pow(pow(x,x - 1.) + pow(x,x)*log(x)*(log(x) + 1.), 2.) +
pow(x,pow(x,x)) * (pow(x,x - 1.) * log(x) +
pow(x,x - 1.) * (log(x) + 1.) +
pow(x,x - 1.) * ((x - 1.)/x + log(x)) +
pow(x,x) * log(x) * pow(log(x) + 1., 2.) )); }
template <class T>
void F(benchmark::State& state) {
T x = state.range(0);
for (auto _ : state) { benchmark::DoNotOptimize(f(x)); }
}
template <class T>
void DF(benchmark::State& state) {
T x = state.range(0);
for (auto _ : state) { benchmark::DoNotOptimize(df(x)); }
}
template <class T>
void DDF(benchmark::State& state) {
T x = state.range(0);
for (auto _ : state) { benchmark::DoNotOptimize(ddf(x)); }
}
template <class T>
void dF(benchmark::State& state) {
T x = state.range(0);
for (auto _ : state) { benchmark::DoNotOptimize(f(dual<T>(x,1))); }
}
template <class T>
void ddF(benchmark::State& state) {
T x = state.range(0);
for (auto _ : state) {
benchmark::DoNotOptimize(f(duals::dual<duals::dual<T>>(x+1_e,1+0_e)));
}
}
BENCHMARK_TEMPLATE(F, float) ->Arg(2); // V_RANGE(1,NF)
BENCHMARK_TEMPLATE(DF, float)->Arg(2); // V_RANGE(1,NF)
BENCHMARK_TEMPLATE(DDF, float)->Arg(2); // V_RANGE(1,NF)
BENCHMARK_TEMPLATE(dF, float)->Arg(2); // V_RANGE(1,NF)
BENCHMARK_TEMPLATE(ddF, float)->Arg(2); // V_RANGE(1,NF)
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char** argv)
{
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}

109
src/include/cppduals/tests/bench_fmt.cpp

@ -0,0 +1,109 @@
/*
* Copyright 2019 Michael Tesch. All rights reserved.
*
* author(s): michael tesch (tesch1@gmail.com)
*
*/
/*! \file bench_fmt.cpp
* \brief benchmarking for formatting
*
* To disable freq scaling:
* cpupower frequency-set --governor performance
* to re-enable freq scaling:
* cpupower frequency-set --governor ondemand
*/
#include <benchmark/benchmark.h>
#include <complex>
#define CPPDUALS_LIBFMT
#define CPPDUALS_LIBFMT_COMPLEX
#include "duals/dual"
template <class T> void B_fmt_1(benchmark::State& state) {
T c(3.4);
for (auto _ : state) {
std::string s;
benchmark::DoNotOptimize(s = fmt::format("{}", c));
}
}
template <class T> void B_ios_1(benchmark::State& state) {
T c(3.4);
for (auto _ : state) {
std::string s;
std::stringstream ss;
ss << c;
s = ss.str();
}
}
template <class T> void B_fmt(benchmark::State& state) {
T c(3.4, 5.6);
for (auto _ : state) {
std::string s;
benchmark::DoNotOptimize(s = fmt::format("{}", c));
}
}
template <class T> void B_fmt_g(benchmark::State& state) {
T c(3.4, 5.6);
for (auto _ : state) {
std::string s;
benchmark::DoNotOptimize(s = fmt::format("{:g}", c));
}
}
template <class T> void B_fmt_star_g(benchmark::State& state) {
T c(3.4, 5.6);
for (auto _ : state) {
std::string s;
benchmark::DoNotOptimize(s = fmt::format("{:*g}", c));
}
}
template <class T> void B_fmt_comma_g(benchmark::State& state) {
T c(3.4, 5.6);
for (auto _ : state) {
std::string s;
benchmark::DoNotOptimize(s = fmt::format("{:,g}", c));
}
}
template <class T> void B_ios(benchmark::State& state) {
T c(3.4, 5.6);
for (auto _ : state) {
std::string s;
std::stringstream ss;
ss << c;
s = ss.str();
}
}
BENCHMARK_TEMPLATE(B_fmt_1, float);
BENCHMARK_TEMPLATE(B_fmt_1, double);
BENCHMARK_TEMPLATE(B_ios_1, float);
BENCHMARK_TEMPLATE(B_ios_1, double);
BENCHMARK_TEMPLATE(B_fmt_g, std::complex<float>);
BENCHMARK_TEMPLATE(B_fmt_star_g, std::complex<float>);
BENCHMARK_TEMPLATE(B_fmt_comma_g, std::complex<float>);
BENCHMARK_TEMPLATE(B_fmt, std::complex<float>);
BENCHMARK_TEMPLATE(B_fmt, std::complex<double>);
BENCHMARK_TEMPLATE(B_fmt, duals::dual<float>);
BENCHMARK_TEMPLATE(B_fmt, duals::dual<double>);
BENCHMARK_TEMPLATE(B_ios, std::complex<float>);
BENCHMARK_TEMPLATE(B_ios, std::complex<double>);
BENCHMARK_TEMPLATE(B_ios, duals::dual<float>);
BENCHMARK_TEMPLATE(B_ios, duals::dual<double>);
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char** argv)
{
std::ios::sync_with_stdio(false);
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}

244
src/include/cppduals/tests/bench_gemm.cpp

@ -0,0 +1,244 @@
//===-- bench_gemm - benchmark dual m*m -----------------------*- C++ -*-===//
//
// Part of the cppduals Project
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
#if defined(__APPLE__) && defined(__clang__)
#include <Accelerate/Accelerate.h>
#else
#ifdef EIGEN_LAPACKE
#include <Eigen/src/misc/lapacke.h>
#else
#include <lapacke.h>
#endif
extern "C" {
//#include <cblas.h>
//#include <cblas_openblas.h>
#include CBLAS_HEADER
}
#endif // defined(__APPLE__) && defined(__clang__)
#include <iostream>
#include <fstream>
#include <complex>
#include <memory>
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Core>
#include <Eigen/Dense>
#include "benchmark/benchmark.h"
using namespace duals;
template< class T > struct type_identity { typedef T type; };
#include <unsupported/Eigen/MatrixFunctions>
/* encode the type into an integer for benchmark output */
template<typename Tp> struct type_num { /* should fail */ };
template<> struct type_num<float> { static constexpr int id = 1; };
template<> struct type_num<double> { static constexpr int id = 2; };
template<> struct type_num<long double> { static constexpr int id = 3; };
template<typename Tp> struct type_num<std::complex<Tp>> { static constexpr int id = 10 + type_num<Tp>::id; };
template<typename Tp> struct type_num<duals::dual<Tp>> { static constexpr int id = 100 + type_num<Tp>::id; };
using duals::dualf;
using duals::duald;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class T> using MatrixX = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
#if 0
#define V_RANGE(V,NF) ->Arg(V*4/NF)->Arg(V*32/NF)->Arg(V*256/NF)->Arg(V*2048/NF)->Arg(V*1)->Complexity()
#else
#define V_RANGE(V,NF) ->Arg(V*64/NF)->Arg(V*128/NF)->Arg(V*256/NF)->Arg(V*512/NF)->Arg(V*1024/NF) ->Arg(V*2048/NF)
#endif
// measure Eigen's matrix-matrix multiplication
template <class T, class U> void B_MatMat(benchmark::State& state) {
int N = state.range(0);
typedef typename Eigen::ScalarBinaryOpTraits<T, U>::ReturnType R;
MatrixX<T> A = MatrixX<T>::Random(N, N);
MatrixX<U> B = MatrixX<U>::Random(N, N);
MatrixX<R> C = MatrixX<R>::Random(N, N);
for (auto _ : state) {
C.noalias() = A * B;
benchmark::ClobberMemory(); // Force c to be written to memory.
}
state.SetComplexityN(state.range(0));
}
template <class T, typename std::enable_if<!duals::is_dual<T>::value>::type* = nullptr>
void matrix_multiplcation(T *A, int Awidth, int Aheight,
T *B, int Bwidth, int Bheight,
T *AB, bool tA, bool tB,
typename type_identity<T>::type beta)
{
int A_height = tA ? Awidth : Aheight;
int A_width = tA ? Aheight : Awidth;
#ifndef NDEBUG
int B_height = tB ? Bwidth : Bheight;
#endif
int B_width = tB ? Bheight : Bwidth;
int m = A_height;
int n = B_width;
int k = A_width;
// Error, width and height should match!
assert(A_width == B_height);
int lda = tA ? m : k;
int ldb = tB ? k : n;
#define TRANSPOSE(X) ((X) ? CblasTrans : CblasNoTrans)
// http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html
if (!is_complex<T>::value) {
if (sizeof(T) == sizeof(float))
cblas_sgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, 1.0, (float *)A, lda, (float *)B, ldb,
std::real(beta), (float *)AB, n);
else
cblas_dgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, 1.0, (double *)A, lda, (double *)B, ldb,
std::real(beta), (double *)AB, n);
}
else {
std::complex<float> alphaf(1,0);
std::complex<double> alpha(1,0);
if (Eigen::NumTraits<T>::digits10() < 10)
cblas_cgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, &alphaf, A, lda, B, ldb, &beta, AB, n);
else
cblas_zgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, &alpha, A, lda, B, ldb, &beta, AB, n);
}
#undef TRANSPOSE
}
template <class T, typename std::enable_if<duals::is_dual<T>::value>::type* = nullptr>
void matrix_multiplcation(T *A, int Awidth, int Aheight,
T *B, int Bwidth, int Bheight,
T *AB, bool tA, bool tB,
typename type_identity<T>::type beta)
{ /* nothing */
}
// measure BLAS matrix-matrix multiplication
template <class Rt> void B_MatMatBLAS(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> B = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> C = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> D = A*B;
for (auto _ : state) {
matrix_multiplcation(A.data(), A.cols(), A.rows(),
B.data(), B.cols(), B.rows(),
C.data(), false, false, (Rt)0.);
benchmark::ClobberMemory(); // Force a to be written to memory.
}
double err = (double)rpart((D - C).norm() / D.norm());
if (err > 1e-6)
state.SkipWithError("BLAS matmat error");
state.SetComplexityN(state.range(0));
}
// measure compiler's matrix-matrix multiplication
template <class Rt, class U> void B_MatMatCXX(benchmark::State& state) {
int N = state.range(0);
std::vector<Rt> a(N*N);
std::vector<Rt> b(N*N);
std::vector<Rt> c(N*N);
for (auto _ : state) {
state.PauseTiming();
a.assign(N*N,1.1);
b.assign(N*N,2.2);
c.assign(N*N,0.);
state.ResumeTiming();
for(int i=0; i<N; ++i)
for(int j=0; j<N; ++j)
for(int k=0; k<N; ++k)
c[i*N+j] += a[i*N+k] * b[k*N+j];
benchmark::ClobberMemory(); // Force a to be written to memory.
}
state.SetComplexityN(state.range(0));
}
// measure eigen's matrix-vector multiplication
template <class Rt, class U> void B_MatVec(benchmark::State& state) {
int N = state.range(0);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> b = MatrixX<Rt>::Random(N, 1);
MatrixX<Rt> c = MatrixX<Rt>::Random(N, 1);
for (auto _ : state) {
c = A * b;
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
#define MAKE_BM_SIMPLE(TYPE1,TYPE2,NF) \
BENCHMARK_TEMPLATE(B_MatMat, TYPE1,TYPE2) V_RANGE(1,NF)
#define MAKE_BENCHMARKS(TYPE1,TYPE2,NF) \
MAKE_BM_SIMPLE(TYPE1,TYPE2,NF); \
BENCHMARK_TEMPLATE(B_MatMatBLAS, TYPE1) V_RANGE(1,NF)
// BENCHMARK_TEMPLATE(B_MatMatBLAS, TYPE1) V_RANGE(1,2*NF);
// BENCHMARK_TEMPLATE(B_VecVecMulCXX, TYPE1,TYPE2) V_RANGE(4,NF);
// BENCHMARK_TEMPLATE(B_MatMatCXX, TYPE1,TYPE2) V_RANGE(1,NF);
MAKE_BENCHMARKS(float, float, 1);
MAKE_BENCHMARKS(complexf, complexf,2);
//MAKE_BM_SIMPLE(dualf, float,2); TODO
MAKE_BM_SIMPLE(dualf, dualf,2);
//MAKE_BM_SIMPLE(cdualf, cdualf,2);
MAKE_BM_SIMPLE(cdualf, cdualf,4);
#if HAVE_BOOST
#include <audi/audi.hpp>
MAKE_BM_SIMPLE(audi::gdual<float>,2);
#endif
// novelty:
//MAKE_BM_SIMPLE(float, complexf,2);
//MAKE_BM_SIMPLE(complexf, float,2);
MAKE_BENCHMARKS(double, double, 1);
MAKE_BENCHMARKS(complexd, complexd,2);
MAKE_BM_SIMPLE(duald, duald,2);
MAKE_BM_SIMPLE(cduald, cduald,4);
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char** argv)
{
#ifndef EIGEN_VECTORIZE
static_assert(false, "no vectorization?");
#endif
#ifndef NDEBUG
static_assert(false, "NDEBUG to benchmark?");
#endif
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}

43
src/include/cppduals/tests/example.cpp

@ -0,0 +1,43 @@
//===-- example.cpp - examples of using <duals/dual> -------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file example.cpp Dual number usage examples
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#if defined(PHASE_1)
#include <duals/dual>
using namespace duals::literals;
template <class T> T f(T x) { return pow(x,pow(x,x)); }
template <class T> T df(T x) { return pow(x,-1. + x + pow(x,x)) * (1. + x*log(x) + x*pow(log(x),2.)); }
template <class T> T ddf(T x) { return (pow(x,pow(x,x)) * pow(pow(x,x - 1.) + pow(x,x)*log(x)*(log(x) + 1.), 2.) +
pow(x,pow(x,x)) * (pow(x,x - 1.) * log(x) +
pow(x,x - 1.) * (log(x) + 1.) +
pow(x,x - 1.) * ((x - 1.)/x + log(x)) +
pow(x,x) * log(x) * pow(log(x) + 1., 2.) )); }
int main()
{
std::cout << " f(2.) = " << f(2.) << "\n";
std::cout << " df(2.) = " << df(2.) << "\n";
std::cout << "ddf(2.) = " << ddf(2.) << "\n";
std::cout << " f(2+1_e) = " << f(2+1_e) << "\n";
std::cout << " f(2+1_e).dpart() = " << f(2+1_e).dpart() << "\n";
duals::hyperduald x(2+1_e,1+0_e);
std::cout << " f((2+1_e) + (1+0_e)_e).dpart().dpart() = " << f(x).dpart().dpart() << "\n";
}
#endif

472
src/include/cppduals/tests/gold-riick.bench_dual.json

@ -0,0 +1,472 @@
{
"context": {
"date": "2019-04-09 23:10:32",
"host_name": "riick.fritz.box",
"executable": "./tests/bench_dual",
"num_cpus": 8,
"mhz_per_cpu": 4200,
"cpu_scaling_enabled": true,
"caches": [
{
"type": "Data",
"level": 1,
"size": 32000000,
"num_sharing": 2
},
{
"type": "Instruction",
"level": 1,
"size": 32000000,
"num_sharing": 2
},
{
"type": "Unified",
"level": 2,
"size": 256000000,
"num_sharing": 2
},
{
"type": "Unified",
"level": 3,
"size": 8192000000,
"num_sharing": 8
}
],
"load_avg": [0.91,0.55,0.49],
"library_build_type": "debug"
},
"benchmarks": [
{
"name": "B_Add<duals::dualf>/2",
"run_name": "B_Add<duals::dualf>/2",
"run_type": "iteration",
"iterations": 824542173,
"real_time": 8.4453082668102275e-01,
"cpu_time": 8.4330497549941574e-01,
"time_unit": "ns"
},
{
"name": "B_Add<duals::dualf>/8",
"run_name": "B_Add<duals::dualf>/8",
"run_type": "iteration",
"iterations": 215407779,
"real_time": 3.3351862932159380e+00,
"cpu_time": 3.3321200252475562e+00,
"time_unit": "ns"
},
{
"name": "B_Add<duals::dualf>/64",
"run_name": "B_Add<duals::dualf>/64",
"run_type": "iteration",
"iterations": 58354344,
"real_time": 1.2061169807457697e+01,
"cpu_time": 1.2049604618980897e+01,
"time_unit": "ns"
},
{
"name": "B_Add<duals::dualf>/512",
"run_name": "B_Add<duals::dualf>/512",
"run_type": "iteration",
"iterations": 7147541,
"real_time": 9.8321614102488141e+01,
"cpu_time": 9.8233268476529204e+01,
"time_unit": "ns"
},
{
"name": "B_Add<duals::dualf>/4096",
"run_name": "B_Add<duals::dualf>/4096",
"run_type": "iteration",
"iterations": 583950,
"real_time": 1.1997066478428608e+03,
"cpu_time": 1.1986074835174250e+03,
"time_unit": "ns"
},
{
"name": "B_Add<duals::dualf>/8192",
"run_name": "B_Add<duals::dualf>/8192",
"run_type": "iteration",
"iterations": 280278,
"real_time": 2.5014722955172806e+03,
"cpu_time": 2.4990253212881489e+03,
"time_unit": "ns"
},
{
"name": "B_Add<std::complex<float>>/2",
"run_name": "B_Add<std::complex<float>>/2",
"run_type": "iteration",
"iterations": 719322979,
"real_time": 9.6203674730458488e-01,
"cpu_time": 9.6122821067280295e-01,
"time_unit": "ns"
},
{
"name": "B_Add<std::complex<float>>/8",
"run_name": "B_Add<std::complex<float>>/8",
"run_type": "iteration",
"iterations": 208022307,
"real_time": 3.3676157142748866e+00,
"cpu_time": 3.3648201247955565e+00,
"time_unit": "ns"
},
{
"name": "B_Add<std::complex<float>>/64",
"run_name": "B_Add<std::complex<float>>/64",
"run_type": "iteration",
"iterations": 41387591,
"real_time": 1.6822550362762875e+01,
"cpu_time": 1.6808160639260215e+01,
"time_unit": "ns"
},
{
"name": "B_Add<std::complex<float>>/512",
"run_name": "B_Add<std::complex<float>>/512",
"run_type": "iteration",
"iterations": 5437243,
"real_time": 1.2896090977804755e+02,
"cpu_time": 1.2885078338415281e+02,
"time_unit": "ns"
},
{
"name": "B_Add<std::complex<float>>/4096",
"run_name": "B_Add<std::complex<float>>/4096",
"run_type": "iteration",
"iterations": 583456,
"real_time": 1.2011305840153541e+03,
"cpu_time": 1.2000171855289859e+03,
"time_unit": "ns"
},
{
"name": "B_Add<std::complex<float>>/8192",
"run_name": "B_Add<std::complex<float>>/8192",
"run_type": "iteration",
"iterations": 281308,
"real_time": 2.5101460142166443e+03,
"cpu_time": 2.5074422056962462e+03,
"time_unit": "ns"
},
{
"name": "B_Sub<duals::dualf>/2",
"run_name": "B_Sub<duals::dualf>/2",
"run_type": "iteration",
"iterations": 728551981,
"real_time": 9.6308006466451668e-01,
"cpu_time": 9.6223501587047333e-01,
"time_unit": "ns"
},
{
"name": "B_Sub<duals::dualf>/8",
"run_name": "B_Sub<duals::dualf>/8",
"run_type": "iteration",
"iterations": 242708995,
"real_time": 2.8970816594436135e+00,
"cpu_time": 2.8945758520404290e+00,
"time_unit": "ns"
},
{
"name": "B_Sub<duals::dualf>/64",
"run_name": "B_Sub<duals::dualf>/64",
"run_type": "iteration",
"iterations": 42881747,
"real_time": 1.6390650175399376e+01,
"cpu_time": 1.6376361322219417e+01,
"time_unit": "ns"
},
{
"name": "B_Sub<duals::dualf>/512",
"run_name": "B_Sub<duals::dualf>/512",
"run_type": "iteration",
"iterations": 5463762,
"real_time": 1.2839805814698460e+02,
"cpu_time": 1.2829124383529179e+02,
"time_unit": "ns"
},
{
"name": "B_Sub<duals::dualf>/4096",
"run_name": "B_Sub<duals::dualf>/4096",
"run_type": "iteration",
"iterations": 579043,
"real_time": 1.2007505781594916e+03,
"cpu_time": 1.1996460815518028e+03,
"time_unit": "ns"
},
{
"name": "B_Sub<duals::dualf>/8192",
"run_name": "B_Sub<duals::dualf>/8192",
"run_type": "iteration",
"iterations": 283021,
"real_time": 2.4547645685559423e+03,
"cpu_time": 2.4523946138272386e+03,
"time_unit": "ns"
},
{
"name": "B_Sub<std::complex<float>>/2",
"run_name": "B_Sub<std::complex<float>>/2",
"run_type": "iteration",
"iterations": 828173889,
"real_time": 8.4244681131040999e-01,
"cpu_time": 8.4170307016284329e-01,
"time_unit": "ns"
},
{
"name": "B_Sub<std::complex<float>>/8",
"run_name": "B_Sub<std::complex<float>>/8",
"run_type": "iteration",
"iterations": 224061326,
"real_time": 3.1243714855868139e+00,
"cpu_time": 3.1216511010025840e+00,
"time_unit": "ns"
},
{
"name": "B_Sub<std::complex<float>>/64",
"run_name": "B_Sub<std::complex<float>>/64",
"run_type": "iteration",
"iterations": 58141628,
"real_time": 1.2089688595827512e+01,
"cpu_time": 1.2079371891684870e+01,
"time_unit": "ns"
},
{
"name": "B_Sub<std::complex<float>>/512",
"run_name": "B_Sub<std::complex<float>>/512",
"run_type": "iteration",
"iterations": 7040996,
"real_time": 9.9699899139357910e+01,
"cpu_time": 9.9613642160853260e+01,
"time_unit": "ns"
},
{
"name": "B_Sub<std::complex<float>>/4096",
"run_name": "B_Sub<std::complex<float>>/4096",
"run_type": "iteration",
"iterations": 581668,
"real_time": 1.2034631524593226e+03,
"cpu_time": 1.2022905179586996e+03,
"time_unit": "ns"
},
{
"name": "B_Sub<std::complex<float>>/8192",
"run_name": "B_Sub<std::complex<float>>/8192",
"run_type": "iteration",
"iterations": 282164,
"real_time": 2.4708674956039085e+03,
"cpu_time": 2.4684340667129668e+03,
"time_unit": "ns"
},
{
"name": "B_Mul<duals::dualf>/2",
"run_name": "B_Mul<duals::dualf>/2",
"run_type": "iteration",
"iterations": 265558620,
"real_time": 2.6450566357631402e+00,
"cpu_time": 2.6427702102082029e+00,
"time_unit": "ns"
},
{
"name": "B_Mul<duals::dualf>/8",
"run_name": "B_Mul<duals::dualf>/8",
"run_type": "iteration",
"iterations": 223502135,
"real_time": 3.1301059652276355e+00,
"cpu_time": 3.1273447656327855e+00,
"time_unit": "ns"
},
{
"name": "B_Mul<duals::dualf>/64",
"run_name": "B_Mul<duals::dualf>/64",
"run_type": "iteration",
"iterations": 30377857,
"real_time": 2.3107029109224477e+01,
"cpu_time": 2.3087210891801917e+01,
"time_unit": "ns"
},
{
"name": "B_Mul<duals::dualf>/512",
"run_name": "B_Mul<duals::dualf>/512",
"run_type": "iteration",
"iterations": 3753884,
"real_time": 1.8687841100299300e+02,
"cpu_time": 1.8672708799739081e+02,
"time_unit": "ns"
},
{
"name": "B_Mul<duals::dualf>/4096",
"run_name": "B_Mul<duals::dualf>/4096",
"run_type": "iteration",
"iterations": 461567,
"real_time": 1.5087395958443526e+03,
"cpu_time": 1.5074006547261827e+03,
"time_unit": "ns"
},
{
"name": "B_Mul<duals::dualf>/8192",
"run_name": "B_Mul<duals::dualf>/8192",
"run_type": "iteration",
"iterations": 229621,
"real_time": 3.0899390212718718e+03,
"cpu_time": 3.0867818709961157e+03,
"time_unit": "ns"
},
{
"name": "B_Mul<std::complex<float>>/2",
"run_name": "B_Mul<std::complex<float>>/2",
"run_type": "iteration",
"iterations": 46285967,
"real_time": 1.5099909223178337e+01,
"cpu_time": 1.5086400139377007e+01,
"time_unit": "ns"
},
{
"name": "B_Mul<std::complex<float>>/8",
"run_name": "B_Mul<std::complex<float>>/8",
"run_type": "iteration",
"iterations": 11661962,
"real_time": 6.0014554242011371e+01,
"cpu_time": 5.9962549440651621e+01,
"time_unit": "ns"
},
{
"name": "B_Mul<std::complex<float>>/64",
"run_name": "B_Mul<std::complex<float>>/64",
"run_type": "iteration",
"iterations": 1468536,
"real_time": 4.7647983704918062e+02,
"cpu_time": 4.7608059795605925e+02,
"time_unit": "ns"
},
{
"name": "B_Mul<std::complex<float>>/512",
"run_name": "B_Mul<std::complex<float>>/512",
"run_type": "iteration",
"iterations": 183082,
"real_time": 3.8213512741184391e+03,
"cpu_time": 3.8181861133262651e+03,
"time_unit": "ns"
},
{
"name": "B_Mul<std::complex<float>>/4096",
"run_name": "B_Mul<std::complex<float>>/4096",
"run_type": "iteration",
"iterations": 22675,
"real_time": 3.0901148974846190e+04,
"cpu_time": 3.0871022888643743e+04,
"time_unit": "ns"
},
{
"name": "B_Mul<std::complex<float>>/8192",
"run_name": "B_Mul<std::complex<float>>/8192",
"run_type": "iteration",
"iterations": 11344,
"real_time": 6.1823873857552790e+04,
"cpu_time": 6.1759684238363785e+04,
"time_unit": "ns"
},
{
"name": "B_Div<duals::dualf>/2",
"run_name": "B_Div<duals::dualf>/2",
"run_type": "iteration",
"iterations": 223074129,
"real_time": 3.1221121030774452e+00,
"cpu_time": 3.1193331432888822e+00,
"time_unit": "ns"
},
{
"name": "B_Div<duals::dualf>/8",
"run_name": "B_Div<duals::dualf>/8",
"run_type": "iteration",
"iterations": 206899949,
"real_time": 3.3619264062599843e+00,
"cpu_time": 3.3588176041551177e+00,
"time_unit": "ns"
},
{
"name": "B_Div<duals::dualf>/64",
"run_name": "B_Div<duals::dualf>/64",
"run_type": "iteration",
"iterations": 29041803,
"real_time": 2.3762771511892577e+01,
"cpu_time": 2.3742337485038277e+01,
"time_unit": "ns"
},
{
"name": "B_Div<duals::dualf>/512",
"run_name": "B_Div<duals::dualf>/512",
"run_type": "iteration",
"iterations": 3605971,
"real_time": 1.9516093806834385e+02,
"cpu_time": 1.9498607337663077e+02,
"time_unit": "ns"
},
{
"name": "B_Div<duals::dualf>/4096",
"run_name": "B_Div<duals::dualf>/4096",
"run_type": "iteration",
"iterations": 412656,
"real_time": 1.7029046954383241e+03,
"cpu_time": 1.7012804781706957e+03,
"time_unit": "ns"
},
{
"name": "B_Div<duals::dualf>/8192",
"run_name": "B_Div<duals::dualf>/8192",
"run_type": "iteration",
"iterations": 199214,
"real_time": 3.5068666004871179e+03,
"cpu_time": 3.5033117702571099e+03,
"time_unit": "ns"
},
{
"name": "B_Div<std::complex<float>>/2",
"run_name": "B_Div<std::complex<float>>/2",
"run_type": "iteration",
"iterations": 38292924,
"real_time": 1.8300814009951591e+01,
"cpu_time": 1.8285078308462527e+01,
"time_unit": "ns"
},
{
"name": "B_Div<std::complex<float>>/8",
"run_name": "B_Div<std::complex<float>>/8",
"run_type": "iteration",
"iterations": 9592683,
"real_time": 7.3376013778254773e+01,
"cpu_time": 7.3309770269694255e+01,
"time_unit": "ns"
},
{
"name": "B_Div<std::complex<float>>/64",
"run_name": "B_Div<std::complex<float>>/64",
"run_type": "iteration",
"iterations": 1196541,
"real_time": 5.8431534145313731e+02,
"cpu_time": 5.8382388986252840e+02,
"time_unit": "ns"
},
{
"name": "B_Div<std::complex<float>>/512",
"run_name": "B_Div<std::complex<float>>/512",
"run_type": "iteration",
"iterations": 150056,
"real_time": 4.6825903796710227e+03,
"cpu_time": 4.6785734792344165e+03,
"time_unit": "ns"
},
{
"name": "B_Div<std::complex<float>>/4096",
"run_name": "B_Div<std::complex<float>>/4096",
"run_type": "iteration",
"iterations": 18718,
"real_time": 3.7536350839790939e+04,
"cpu_time": 3.7500307404637017e+04,
"time_unit": "ns"
},
{
"name": "B_Div<std::complex<float>>/8192",
"run_name": "B_Div<std::complex<float>>/8192",
"run_type": "iteration",
"iterations": 9342,
"real_time": 7.4837835688738924e+04,
"cpu_time": 7.4762648469278734e+04,
"time_unit": "ns"
}
]
}

1160
src/include/cppduals/tests/gold-riick.bench_eigen.json
File diff suppressed because it is too large
View File

142
src/include/cppduals/tests/runbench.sh

@ -0,0 +1,142 @@
#!/usr/bin/env bash
#
# run benchmarks -
#
CMDLINE="$0 $@"
SCRIPT=$(basename "$0")
SRCDIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OnError() {
echo "$SCRIPT: Error on line ${BASH_LINENO[0]}, exiting."
exit 1
}
trap OnError ERR
HOSTTAG=$(hostname | cut -d . -f 1)
VERBOSE=1
GOLDBASE="$SRCDIR/gold-${HOSTTAG}"
BENCH_LIST=
BENCH_ARGS=
MAKE_ARGS=
TAG=
usage () {
if [ -t 3 ]; then echo "$SCRIPT failed, see log" >&3 ; fi
cat <<EOF
usage:
${SCRIPT} <benchmarks> [options...]
where <benchmarks> are [bench_eigen|bench_dual]
where [options...] are:
-g|--makegold - save ouput to the 'gold' file standard location
-T|--tag <tag> - add tag to results file [$TAG]
-t|--test <test> - filter benchmark tests against <test> [*]
-o|--output <base> - output file name base [$OUTFILE]
-f|--fast - run fast, at the great expense of accurate measurement
-m|--medium - run medium fast, at the medium expense of accurate measurement
-v|--verbose - be more verbose (can add multiple times)
-q|--quiet - be more quiet (can add multiple times)
-h|--help - print this usage message and exit
current bench1 args: ${BENCH_ARGS}
EOF
exit 1
}
# process command line args
while [ $# -gt 0 ]; do
key="$1"
case $key in
-g|--makegold) OUTFILE="$GOLDBASE" ;;
-T|--tag) TAG="-$2" ; shift ;;
-o|--output) OUTFILE="$2"; shift ;;
-t|--test)
BENCH_ARGS="${BENCH_ARGS} --benchmark_filter=$2"
shift
;;
-f|--fast)
BENCH_ARGS="${BENCH_ARGS} --benchmark_min_time=0.001"
;;
-m|--medium)
BENCH_ARGS="${BENCH_ARGS} --benchmark_min_time=0.05"
;;
-h|help) usage ;;
-v|--verbose)
VERBOSE=$(( VERBOSE + 1 ))
MAKE_ARGS="${MAKE_ARGS} VERBOSE=1"
;;
-q|--quiet) VERBOSE=$(( VERBOSE - 1 )) ;;
*)
if [ -f "${SRCDIR}/${key}.cpp" ]; then
BENCH_LIST="${BENCH_LIST} ${key}"
shift
continue
fi
# unknown option
echo "unknown option $key"
usage
;;
esac
shift
done
# default
if [ -z "${BENCH_LIST}" ]; then
BENCH_LIST=bench_dual
fi
BENCH_ARGS="${BENCH_ARGS} --benchmark_out_format=json"
ret=0
for NAME in ${BENCH_LIST}; do
GOLDFILE=${GOLDBASE}.${NAME}${TAG}.json
TMPFILE=$(mktemp ./bench.XXXXXXXXX)
# if there's no gold reference yet, by default create one
if [ -z "$OUTFILE" ]; then
if [ ! -f "$GOLDFILE" ]; then
echo "No gold file found, creating one..."
REALOUT=$GOLDFILE
else
REALOUT=bo-${NAME}${TAG}.json
fi
else
REALOUT=${OUTFILE}.${NAME}${TAG}.json
fi
BENCH_ARGS="${BENCH_ARGS} --benchmark_out=${TMPFILE}"
#BENCH_ARGS="${BENCH_ARGS} --benchmark_counters_tabular=true"
#BENCH_ARGS="${BENCH_ARGS} --benchmark_repetitions=1000"
echo "GOLDFILE=$GOLDFILE"
echo "TMPFILE =$TMPFILE"
echo "OUTFILE =$OUTFILE"
echo "REALOUT =$REALOUT"
echo "Making ${NAME}${TAG} $MAKE_ARGS"
make -j4 "${NAME}" $MAKE_ARGS
echo "Running benchmarks: ./tests/${NAME} $BENCH_ARGS"
#echo " : output in ${NAME}.out"
if ! ./tests/${NAME} $BENCH_ARGS ; then
echo "failed $NAME"
ret=1
continue
fi
if [ "${REALOUT}" != "$TMPFILE" ]; then
mv "$TMPFILE" "${REALOUT}"
fi
if [ "${REALOUT}" != "$GOLDFILE" ]; then
echo "comparing with $GOLDFILE"
./thirdparty/benchmarkX/src/benchmarkX/tools/compare.py benchmarks "$GOLDFILE" "${REALOUT}"
fi
#./thirdparty/benchmarkX/src/benchmarkX/tools/compare.py filters ./bench_eigen B_Pade B_Expm
echo "Benchmark ouput in '${REALOUT}'"
done
exit $ret

122
src/include/cppduals/tests/sandbox.cpp

@ -0,0 +1,122 @@
//===-- test_dual.cpp - test duals/dual -------------------------*- C++ -*-===//
//
// Part of the cppduals Project
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* just a place to play around and get dirty.
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include <math.h>
#include <iostream>
#include <iomanip>
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <unsupported/Eigen/MatrixFunctions>
using std::cout;
using std::cerr;
using duals::dualf;
using duals::duald;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
typedef std::complex<hyperdualf> chyperdualf;
using duals::dual_traits;
using namespace duals::literals;
template <class eT, int N=Eigen::Dynamic, int P=N> using emtx = Eigen::Matrix<eT, N, P>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int P=N> using ecf = Eigen::Matrix<complexf, N, P> ;
template <int N=2, int P=N> using edf = Eigen::Matrix<dualf, N, P> ;
template <int N=2, int P=N> using ecdf = Eigen::Matrix<cdualf, N, P> ;
#define PO_EXPR_TYPE(...) typename std::decay<decltype( __VA_ARGS__ )>::type::PlainObject
template <class T = int>
class Rando { T x; };
struct Randa { int x; };
namespace std {
template <class T>
struct common_type<Rando<T>,T> { typedef Rando<T> type; };
}
#if 0
int main(int argc, char * argv[])
{
emtx<cduald,50> A,B,C;
//emtx<complexd,50> A,B,C;
C = A * B;
}
#elif 0
int main(int argc, char * argv[])
{
typedef double T;
T h(T(1) / (1ull << (std::numeric_limits<T>::digits / 3)));
#define func erfc
for (double x = 0; x < 4; x += .21) {
std::cout << " erf(" << x << ") = " << func (x) << " , =" << (func (x+h)- func (x))/h << "\n";
std::cout << "d(erf" << x << ") = " << func (x + 1_e) << "\n";
}
}
#else
template <class T> T f(T x) { return pow(x,pow(x,x)); }
template <class T> T df(T x) { return pow(x,-1 + x + pow(x,x)) * (1 + x*log(x) + x*pow(log(x),2)); }
template <class T> T ddf(T x) { return (pow(x,pow(x,x)) * pow(pow(x,x - 1) + pow(x,x)*log(x)*(log(x) + 1), 2) +
pow(x,pow(x,x)) * (pow(x,x - 1) * log(x) +
pow(x,x - 1) * (log(x) + 1) +
pow(x,x - 1) * ((x - 1)/x + log(x)) +
pow(x,x) * log(x) * pow(log(x) + 1, 2) )); }
int main(int argc, char * argv[])
{
dualf h;
dualf xx(1);
hyperdualf y;
hyperdualf w(1);
hyperdualf z(xx,h);
hyperdualf a(xx);
emtx<double> ed;
emtx<float> ef;
emtx<complexd> ecd;
emtx<complexf> ecf_;
emtx<duald> edd;
emtx<dualf,2> edf_;
emtx<cduald> ecdd;
emtx<cdualf> ecdf_;
std::cout << " f(2.) = " << f(2.) << "\n";
std::cout << " df(2.) = " << df(2.) << "\n";
std::cout << "ddf(2.) = " << ddf(2.) << "\n";
std::cout << " f(2+1_e) = " << f(2+1_e) << "\n";
std::cout << " f(2+1_e).dpart() = " << f(2+1_e).dpart() << "\n";
duals::hyperduald x(2+1_e,1+0_e);
std::cout << " f((2+1_e) + (1+0_e)_e).dpart().dpart() = " << f(x).dpart().dpart() << "\n";
std::cout << " c((2+1_e) + (1+0_e)_e).dpart().dpart() = " << cbrt(x).dpart().dpart() << "\n";
}
#endif

208
src/include/cppduals/tests/test_1.cpp

@ -0,0 +1,208 @@
//===-- test_1.cpp - test duals/dual ------------------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_eigen Dual number Eigen integration tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <fstream>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include <unsupported/Eigen/MatrixFunctions>
#include <unsupported/Eigen/AutoDiff>
#include "eexpokit/padm.hpp"
#include "gtest/gtest.h"
using duals::rpart;
using duals::dpart;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int K = N> using ecf = Eigen::Matrix<complexf, N, K> ;
template <int N=2, int K = N> using edf = Eigen::Matrix<dualf, N, K> ;
template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); }
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
/// Simple taylor series, truncated when |S| is "small enough"
template <class DerivedA, typename ReturnT = typename DerivedA::PlainObject>
ReturnT
expm4(const Eigen::EigenBase<DerivedA> & A_,
typename DerivedA::RealScalar mn
= std::numeric_limits<typename DerivedA::RealScalar>::epsilon() * 10
//= 1.L/(1ull << (std::numeric_limits<typename DerivedA::RealScalar>::digits / 3))
)
{
//std::cerr << "do PO:" << type_name<typename DerivedA::PlainObject>() << "\n";
typedef typename DerivedA::RealScalar Real;
using std::isfinite;
using std::pow;
const DerivedA & A = A_.derived();
int maxt = std::numeric_limits<Real>::digits;
int s = (int)log2(rpart(A.derived().norm())) + 1;
s = std::max(0, s);
auto B = A * pow(Real(2), -s);
ReturnT R(A.rows(), A.cols());
R.setIdentity();
R += B;
ReturnT S = B;
int ni = 0;
for (int ii = 2; ii < maxt; ii++) {
ni++;
S = Real(1.0/ii) * S * B;
R += S;
auto Sn = S.norm();
if (!isfinite(Sn)) {
std::cout << "expm() non-finite norm:" << Sn << " at " << ii << "\n";
std::cout << " |R| = " << R.norm() << " s=" << s << "\n"
<< " |A| = " << rpart(A.real().norm()) << "\n"
<< " |A/2^s|=" << rpart(A.real().norm()/pow(2,s)) << "\n";
break;
}
// converged yet?
if (Sn < mn)
break;
if (ii == maxt - 1) {
std::cout << "expm() didn't converge in " << maxt << " |S| = " << Sn << "\n";
throw std::invalid_argument("no converge");
}
}
//int ss = s;
for (; s; s--)
R = R * R;
//std::cout << "expm s=" << ss << " ni=" << ni << " tol=" << mn << " |S|= " << S.norm() << "\n";
return R;
}
template <class T, int NN = 30, class DT = dual<T> >
void dexpm() {
//typedef std::complex<float> T;
//typedef std::complex<dual<T>> dualt;
T tol = NN * NN * 1000 * Eigen::NumTraits<T>::epsilon();
#define N2 2*NN
// check dual
emtx<T,NN> A = emtx<T,NN>::Random();
emtx<T,NN> V = emtx<T,NN>::Random();
emtx<T,NN> dA1,dA2,dA3,eA1,eA2,eA3,C;
// dA/dV method 1
emtx<T,N2> AVA = emtx<T,N2>::Zero();
AVA.block( 0, 0,NN,NN) = A;
AVA.block( 0,NN,NN,NN) = V;
AVA.block(NN,NN,NN,NN) = A;
AVA = AVA.exp();
//AVA = eexpokit::padm(AVA,13);
eA1 = AVA.block(0,0,NN,NN);
dA1 = AVA.block(0,NN,NN,NN);
// dA/dV method 2
emtx<DT, NN> a,b,c;
a = A + DT(0,1) * V;
b = expm4(a);
// TODO: find a second trustworthy expm function, padm() and a.exp()
// arent reliable here.
//c = eexpokit::padm(a,13);
//C = eexpokit::padm(A,13);
//c = a.exp();
eA2 = rpart(b);
dA2 = dpart(b);
eA3 = rpart(c);
dA3 = dpart(c);
#if 0
std::ofstream A_(type_name<T>().str() + std::to_string(NN) + "A.dat");
A_ << A;
std::ofstream V_(type_name<T>().str() + std::to_string(NN) + "V.dat");
V_ << V;
std::ofstream _(type_name<T>().str() + std::to_string(NN) + "_.dat");
_ << "A=" << A << "\n";
_ << "V=" << V << "\n";
_ << "eA1=" << eA1 << "\n";
_ << "dA1=" << dA1 << "\n";
//_ << "a=" << a << "\n";
_ << "b=" << b << "\n";
_ << "c=" << c << "\n";
_ << "C=" << C << "\n";
std::cout << "a:" << type_name<decltype(a)>() << "\n";
#endif
EXPECT_LT((eA1 - eA2).norm(), tol) << "eA1=" << eA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "eA2=" << eA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "b=" << b.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
EXPECT_LT((dA1 - dA2).norm(), tol) << "dA1=" << dA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "dA2=" << dA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "b=" << b.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
#if 0 // see above.
EXPECT_LT((eA1 - eA3).norm(), tol) << "eA1=" << eA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "eA3=" << eA3.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "c=" << c.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
EXPECT_LT((dA1 - dA3).norm(), tol) << "dA1=" << dA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "dA3=" << dA3.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "c=" << c.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
#endif
}
#if defined(PHASE_1)
TEST(dexpm, float2) { dexpm<float,2>(); }
TEST(dexpm, float4) { dexpm<float,4>(); }
#elif defined(PHASE_2)
TEST(dexpm, double2) { dexpm<double,2>(); }
TEST(dexpm, double4) { dexpm<double,4>(); }
#endif
int main(int argc, char **argv)
{
std::ptrdiff_t l1, l2, l3;
Eigen::internal::manage_caching_sizes(Eigen::GetAction, &l1, &l2, &l3);
std::cout << "l1=" << l1 << " l2=" << l2 << " l3=" << l3 << "\n";
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

1108
src/include/cppduals/tests/test_dual.cpp
File diff suppressed because it is too large
View File

549
src/include/cppduals/tests/test_eigen.cpp

@ -0,0 +1,549 @@
//===-- test_funcs.cpp - test duals/dual ------------------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_eigen Dual number Eigen integration tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include <unsupported/Eigen/MatrixFunctions>
//#include <unsupported/Eigen/AutoDiff>
#include "eexpokit/padm.hpp"
#include "gtest/gtest.h"
using duals::rpart;
using duals::dpart;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int K = N> using ecf = Eigen::Matrix<complexf, N, K> ;
template <int N=2, int K = N> using edf = Eigen::Matrix<dualf, N, K> ;
template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); }
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B))
#define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B))
#define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B))
#define EXPECT_DNEAR(A,B,tol) \
EXPECT_NEAR(rpart(A), rpart(B),tol); \
EXPECT_NEAR(dpart(A), dpart(B),tol)
/// Simple taylor series, truncated when |S| is "small enough"
template <class DerivedA, typename ReturnT = typename DerivedA::PlainObject>
ReturnT
expm4(const Eigen::EigenBase<DerivedA> & A_,
typename DerivedA::RealScalar mn = std::numeric_limits<typename DerivedA::RealScalar>::epsilon() * 1000)
{
//std::cerr << "do PO:" << type_name<typename DerivedA::PlainObject>() << "\n";
typedef typename DerivedA::RealScalar Real;
using std::isfinite;
const DerivedA & A = A_.derived();
int maxt = std::numeric_limits<Real>::digits;
int s = log2(rpart(A.derived().norm())) + 1;
s = std::max(0, s);
auto B = A * pow(Real(2), -s);
ReturnT R(A.rows(), A.cols());
R.setIdentity();
R += B;
ReturnT S = B;
for (int ii = 2; ii < maxt; ii++) {
S = S * B * Real(1.0/ii);
R += S;
auto Sn = S.norm();
if (!isfinite(Sn)) {
std::cout << "expm() non-finite norm:" << Sn << " at " << ii << "\n";
std::cout << " |R| = " << R.norm() << " s=" << s << "\n"
<< " |A| = " << rpart(A.real().norm()) << "\n"
<< " |A/2^s|=" << rpart(A.real().norm()/pow(2,s)) << "\n";
break;
}
// converged yet?
if (Sn < mn)
break;
if (ii == maxt - 1) {
std::cout << "expm() didn't converge in " << maxt << " |S| = " << Sn << "\n";
throw std::invalid_argument("no converge");
}
}
for (; s; s--)
R = R * R;
return R;
}
TEST(Eigen, NumTraits) {
//::testing::StaticAssertTypeEq<Eigen::NumTraits<duals::dual<float>>::Real, float>();
_EXPECT_TRUE(std::is_same<typename Eigen::NumTraits<duals::dual<float>>::Real, dualf>);
_EXPECT_TRUE(std::is_same<typename Eigen::NumTraits<cdualf>::Real, dualf>);
EXPECT_EQ(Eigen::NumTraits<duals::dual<float>>::dummy_precision(),
Eigen::NumTraits<float>::dummy_precision());
EXPECT_EQ(Eigen::NumTraits<duals::dual<float>>::digits10(),
Eigen::NumTraits<float>::digits10());
EXPECT_EQ(Eigen::NumTraits<cdualf>::dummy_precision(),
Eigen::NumTraits<float>::dummy_precision());
}
TEST(Eigen, construction)
{
emtx<double> ed;
emtx<float> ef;
emtx<complexd> ecd;
emtx<complexf> ecf;
emtx<duald> edd;
emtx<dualf> edf_;
emtx<cduald> ecdd;
emtx<cdualf> ecdf_;
}
TEST(Eigen, sparse)
{
smtx<double> ed;
smtx<float> ef;
smtx<complexd> ecd;
smtx<complexf> ecf;
smtx<duald> edd;
smtx<dualf> edf_;
smtx<cduald> ecdd;
smtx<cdualf> ecdf_;
}
TEST(Eigen, expr_type_dense) {
emtx<double> ed;
emtx<float> ef;
emtx<complexd> ecd;
emtx<complexf> ecf;
emtx<duald> edd;
emtx<dualf> edf_;
emtx<cduald> ecdd;
emtx<cdualf> ecdf_;
//_EXPECT_TRUE(std::is_base_of<Eigen::EigenBase<U>,U >::value);
//_EXPECT_TRUE(std::is_same<std::common_type<emtx<dualf>,dualf>::type, emtx<dualf>>);
ecf = ecf * 1;
#define PO_EXPR_TYPE(...) typename std::decay<decltype( __VA_ARGS__ )>::type::PlainObject
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecf*1), emtx<complexf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecf + ecf), emtx<complexf>>);
//_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecf * edf_), emtx<cdualf>>); [1]
//_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecf * 1_ef), emtx<cdualf>>); [1]
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecf * cdualf(1,2)), emtx<cdualf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(edf_ * 2), emtx<dualf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(edf_ * cdualf(2,2)), emtx<cdualf>>);
static_assert(!duals::can_promote<dualf, emtx<dualf>>::value, "nope");
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(edf_ * 2_ef), emtx<dualf>>);
//_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(edf_ * 2_e), emtx<duald>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecf * complexf(1,2)), emtx<complexf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecdf_ * 1), emtx<cdualf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecdf_ * 2_ef), emtx<cdualf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecdf_ * complexf(1,2)), emtx<cdualf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ecdf_ * cdualf(1_ef,2_ef)), emtx<cdualf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(edd * 1_e), emtx<duald>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(edd * 1_ef), emtx<duald>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(ed*1), emtx<double>>);
auto a1 = ecf * 1;
auto a2 = ecf * ecf;
//auto a3 = ecf * edf_; [1]
//auto a4 = ecf * 1_ef; [1]
auto a5 = ecf * cdualf(1,2);
auto a6 = edf_ * 2;
auto a7 = edf_ * 2_ef;
auto a8 = ecf * complexf(1,2);
auto a9 = ecdf_ * 1;
ecdf_ = ecdf_ * complexf(1,2);
ecdf_ = ecdf_ * cdualf(1_ef,2_ef);
auto a12 = edd * 1_e;
auto a13 = ed * 1;
auto A1 = a1.eval(); A1 += A1;
auto A2 = a2.eval(); A2 += A2;
//auto A3 = a3.eval(); A3 += A3; [1]
//auto A4 = a4.eval(); A4 += A4; [1]
auto A5 = a5.eval(); A5 += A5;
auto A6 = a6.eval(); A6 += A6;
auto A7 = a7.eval(); A7 += A7;
auto A8 = a8.eval(); A8 += A8;
auto A9 = a9.eval(); A9 += A9;
auto A12 = a12.eval(); A12 += A12;
auto A13 = a13.eval(); A13 += A13;
}
TEST(init, Constant) {
edf<3> a = edf<3>::Constant(3,3, 5 + 8_ef);
ecdf<3> b = ecdf<3>::Constant(3,3, cdualf(4,2 + 3_ef));
EXPECT_EQ(a(1,1), 5 + 8_ef);
EXPECT_EQ(b(0,1), cdualf(4,2 + 3_ef));
EXPECT_TRUE((a.array() < 6).all());
EXPECT_FALSE((a.array() != 5 + 8_ef).any());
EXPECT_EQ((a.array() == 5 + 8_ef).count(), 9);
}
TEST(init, setIdentity) {
edf<3> a = edf<3>::Constant(3,3, 5 + 8_ef);
ecdf<3> b = ecdf<3>::Constant(3,3, cdualf(4,2 + 3_ef));
a.setIdentity();
b.setIdentity();
EXPECT_EQ(a(0,0), 1);
EXPECT_EQ(a(0,1), 0);
EXPECT_EQ(a(0,2), 0);
EXPECT_EQ(a(1,0), 0);
EXPECT_EQ(a(1,1), 1);
EXPECT_EQ(a(1,2), 0);
EXPECT_EQ(a(2,0), 0);
EXPECT_EQ(a(2,1), 0);
EXPECT_EQ(a(2,2), 1);
EXPECT_EQ(b(0,0).real(), 1);
EXPECT_EQ(b(0,1).real(), 0);
EXPECT_EQ(b(0,2).real(), 0);
EXPECT_EQ(b(1,0).real(), 0);
EXPECT_EQ(b(1,1).real(), 1);
EXPECT_EQ(b(1,2).real(), 0);
EXPECT_EQ(b(2,0).real(), 0);
EXPECT_EQ(b(2,1).real(), 0);
EXPECT_EQ(b(2,2).real(), 1);
}
TEST(init, setZero) {
edf<3> a = edf<3>::Constant(3,3, 5 + 8_ef);
ecdf<3> b = ecdf<3>::Constant(3,3, cdualf(4,2 + 3_ef));
EXPECT_EQ(a(1,1), 5 + 8_ef);
a.setZero();
b.setZero();
EXPECT_EQ(a(0,0), 0);
EXPECT_EQ(a(0,1), 0);
EXPECT_EQ(a(0,2), 0);
EXPECT_EQ(a(1,0), 0);
EXPECT_EQ(a(1,1), 0);
EXPECT_EQ(a(1,2), 0);
EXPECT_EQ(a(2,0), 0);
EXPECT_EQ(a(2,1), 0);
EXPECT_EQ(a(2,2), 0);
EXPECT_EQ(b(0,0).real(), 0);
EXPECT_EQ(b(0,1).real(), 0);
EXPECT_EQ(b(0,2).real(), 0);
EXPECT_EQ(b(1,0).real(), 0);
EXPECT_EQ(b(1,1).real(), 0);
EXPECT_EQ(b(1,2).real(), 0);
EXPECT_EQ(b(2,0).real(), 0);
EXPECT_EQ(b(2,1).real(), 0);
EXPECT_EQ(b(2,2).real(), 0);
EXPECT_EQ(b(0,0).imag(), 0);
EXPECT_EQ(b(0,1).imag(), 0);
EXPECT_EQ(b(0,2).imag(), 0);
EXPECT_EQ(b(1,0).imag(), 0);
EXPECT_EQ(b(1,1).imag(), 0);
EXPECT_EQ(b(1,2).imag(), 0);
EXPECT_EQ(b(2,0).imag(), 0);
EXPECT_EQ(b(2,1).imag(), 0);
EXPECT_EQ(b(2,2).imag(), 0);
}
TEST(init, LinSpaced) {
ecf<3,1> a = ecf<3,1>::LinSpaced(3, 4, complexf(6,7));
EXPECT_EQ(a(0).real(), 4);
EXPECT_EQ(a(1).real(), 5);
EXPECT_EQ(a(2).real(), 6);
edf<3,1> b = edf<3,1>::LinSpaced(3, 4, 6 + 6_ef);
EXPECT_EQ(b(0), 4);
EXPECT_EQ(b(1), 5 + 3_ef);
EXPECT_EQ(b(2), 6 + 6_ef);
}
TEST(init, Random) {
complexf c = emtx<complexf,1>::Random()(0,0);
EXPECT_NE(c.real(), 0);
EXPECT_NE(c.imag(), 0);
typedef dualf Rt;
using duals::random;
Rt b = emtx<Rt,1>::Random()(0,0);
EXPECT_NE(b.rpart(), 0);
//EXPECT_NE(b.dpart(), 0); //
edf<3> j = edf<3>::Random(3,3);
EXPECT_NE(j(1,2).rpart(), 0);
//EXPECT_NE(j(2,0).dpart(), 0); //
ecdf<3> k = ecdf<3>::Random(3,3);
EXPECT_NE(k(0,1).real().rpart(), 0);
//EXPECT_NE(k(1,1).imag().dpart(), 0); //
using duals::randos::random2;
dualf x = random2<dualf>();
EXPECT_NE(x.rpart(), 0);
EXPECT_NE(x.dpart(), 0);
duald y = random2<duald>();
EXPECT_NE(y.rpart(), 0);
EXPECT_NE(y.dpart(), 0);
//EXPECT_NE(k(1,1).imag().dpart(), 0); //
}
TEST(assign, ops) {
emtx<double> ed;
emtx<float> ef;
emtx<complexd> ecd;
emtx<complexf> ecf;
emtx<duald> edd;
emtx<dualf> edf_;
emtx<cduald> ecdd;
emtx<cdualf> ecdf_;
ed *= 2;
ef *= 2;
//ecd *= 2;
//ecf *= 2;
//ecd *= 2_e;
//ecf *= 2_ef;
edd *= 2;
edf_ *= 2;
edd *= 2_e;
edf_ *= 2_ef;
//ecdd *= 2;
// ecdf_ *= 2;
}
TEST(Array, math) {
int N = 5;
emtx<float> x(N,1);
emtx<float> y(N,1);
emtx<float> z(N,1);
x.array() += 1;
x += y + z;
x *= 2;
emtx<duald> a(N,1);
emtx<duald> A(N,1);
emtx<duald> c(N,1);
a.array() = 1 + 1_e;
a.array() += 3_e;
a.array() = 0;
a.array() += 1;
A.array() += 2;
c = a + A;
c = a * 2;
c = a * 2_e;
c = 2 * a;
c = (3 + 2_e) * a;
c *= 3;
c *= 3_e;
EXPECT_EQ(c(N-1), 27_e);
}
TEST(access, CwiseRpartOp) {
// on float matrices (pass-through)
emtx<float,3> a, b = emtx<float,3>::Random();
a = b.unaryExpr(duals::CwiseRpartOp<float>());
EXPECT_NE(a.norm(), 0);
// on dual<float> matrices
emtx<dualf,3> d;
a = d.unaryExpr(duals::CwiseRpartOp<dualf>());
a = d.unaryExpr(duals::CwiseDpartOp<dualf>());
a = rpart(d);
a = dpart(d);
// on complex<dual<float>> matrices
emtx<complexf,3> g, f = emtx<complexf,3>::Random();
emtx<cdualf,3> e;
e.array() = f.array().cast<cdualf>() - 1_ef * f.array().cast<cdualf>();
g = e.unaryExpr(duals::CwiseRpartOp<cdualf>());
EXPECT_EQ((f-g).norm(), 0);
g = f.unaryExpr(duals::CwiseRpartOp<complexf>());
EXPECT_EQ((f-g).norm(), 0);
g = rpart(f);
EXPECT_EQ((f-g).norm(), 0);
g = e.unaryExpr(duals::CwiseDpartOp<cdualf>());
EXPECT_EQ((f+g).norm(), 0);
g = f.unaryExpr(duals::CwiseDpartOp<complexf>());
EXPECT_EQ((g).norm(), 0);
g = dpart(f);
EXPECT_EQ((g).norm(), 0);
}
TEST(access, CwiseDpartOp) {
// on float matrices (pass-through)
emtx<float,3> a, b = emtx<float,3>::Random();
a = b.unaryExpr(duals::CwiseDpartOp<float>());
EXPECT_EQ(a.norm(), 0);
// on dual<float> matrices
emtx<dualf,3> d = b - 1_ef * b;
a = d.unaryExpr(duals::CwiseDpartOp<dualf>());
EXPECT_NE(a.norm(), 0);
EXPECT_EQ((a+b).norm(), 0);
// on complex<dual<float>> matrices
emtx<complexf,3> g, f = emtx<complexf,3>::Random();
emtx<cdualf,3> e;
e.array() = f.array().cast<cdualf>() - 1_ef * f.array().cast<cdualf>();
g = e.unaryExpr(duals::CwiseDpartOp<cdualf>());
EXPECT_EQ((g+f).norm(), 0);
d = e.real();
EXPECT_NE(d.norm(), 0);
}
TEST(measure, norm) {
typedef emtx<complexf, 3> MatrixC;
MatrixC c = (MatrixC() << 1,2,3, 4,5,6, 7,8,9).finished();
EXPECT_EQ(c.cwiseAbs().colwise().sum().maxCoeff(), complexf(18));
//EXPECT_EQ(c.maxCoeff(), complexf(9));
//typedef duald Rt;
typedef dualf Rt;
//typedef cdualf Rt;
typedef emtx<Rt, 3> MatrixD;
Rt b = 1+0_ef;
b = 3;
Rt d(1);
MatrixD x;
x << d;
MatrixD a = (MatrixD() << 1,2,3, 4,5+5_ef,6, 7,8,9).finished();
//typename MatrixD::Index index;
EXPECT_EQ(a.sum(), 45 + 5_ef);
EXPECT_NEAR(rpart(a.norm()), 16.8819430161341337282, 1e-5);
EXPECT_NEAR(rpart(a.mean()), 5, 1e-5);
EXPECT_NEAR(dpart(a.mean()), 0.555555555555555, 1e-5);
EXPECT_EQ(a.minCoeff(), 1);
EXPECT_EQ(a.maxCoeff(), 9);
EXPECT_EQ(a.trace(), 15 + 5_ef);
EXPECT_EQ(a.squaredNorm(), 285+0_e);
EXPECT_EQ(a.lpNorm<1>(), 45 + 5_ef);
//EXPECT_EQ(a.lpNorm<Eigen::Infinity>(), 9);
// 1-norm
//EXPECT_EQ(a.colwise().lpNorm<1>().maxCoeff(), 45 + 5_ef);
EXPECT_EQ(a.cwiseAbs().colwise().sum().maxCoeff(), 18);
}
TEST(dual_decay, stat) {
emtx<float> ef;
emtx<complexd> ecd;
emtx<complexf> ecf;
emtx<duald> edd;
emtx<dualf> edf_;
emtx<cduald> ecdd;
emtx<cdualf> ecdf_;
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(rpart(ef)), emtx<float>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(dpart(ef)), emtx<float>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(rpart(edf_)), emtx<float>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(dpart(edf_)), emtx<float>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(rpart(ecdf_)), emtx<complexf>>);
_EXPECT_TRUE(std::is_same<PO_EXPR_TYPE(dpart(ecdf_)), emtx<complexf>>);
}
TEST(dpart, matrix) {
emtx<float,3> a = emtx<float,3>::Random(3,3);
emtx<float,3> b = emtx<float,3>::Random(3,3);
emtx<float,3> c = emtx<float,3>::Random(3,3);
emtx<float,3> d = emtx<float,3>::Random(3,3);
emtx<dualf,3> A = a + 1_ef * b;
emtx<dualf,3> B = c + 1_ef * d;
emtx<cdualf,3> AA;
emtx<complexf,3> BB,CC;
AA.real() = A;
AA.imag() = B;
BB.real() = a;
BB.imag() = c;
CC.real() = b;
CC.imag() = d;
EXPECT_EQ((rpart(A) - a).norm(),0);
EXPECT_EQ((dpart(A) - b).norm(),0);
EXPECT_EQ((rpart(AA) - BB).norm(),0);
EXPECT_EQ((dpart(AA) - CC).norm(),0);
}
TEST(func, expm) {
typedef float T;
typedef dual<T> dualt;
typedef std::complex<dual<T>> cdualt;
#define NN 3
#define N2 6
emtx<dualt, NN> a,b;
a = emtx<dualt, NN>::Random();
a.array() += 1.1 + 2.2_ef;
a.setZero();
a = eexpokit::padm(a);
EXPECT_LT((a - emtx<dualt, NN>::Identity()).norm(), 1e-6) << "a=" << a << "\n";
a *= 1+2_e;
EXPECT_LT((a - emtx<dualt, NN>::Identity()).norm(), 1e-6) << "a=" << a << "\n";
emtx<cdualt, NN> c;
//b = a + 1_e * emtx<cdualf, 3>::Random();
c.setZero();
c = c.exp();
//c = expm4(c);
EXPECT_LT((c - emtx<cdualf, NN>::Identity()).norm(), 1e-6) << "b=" << b << "\n";
#undef NN
#undef N2
}
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char **argv)
{
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

215
src/include/cppduals/tests/test_expm.cpp

@ -0,0 +1,215 @@
//===-- test_funcs.cpp - test duals/dual ------------------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_eigen Dual number Eigen integration tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include <unsupported/Eigen/MatrixFunctions>
#include <unsupported/Eigen/AutoDiff>
#include "eexpokit/padm.hpp"
#include "gtest/gtest.h"
using duals::rpart;
using duals::dpart;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int K = N> using ecf = Eigen::Matrix<complexf, N, K> ;
template <int N=2, int K = N> using edf = Eigen::Matrix<dualf, N, K> ;
template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); }
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B))
#define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B))
#define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B))
#define EXPECT_DNEAR(A,B,tol) \
EXPECT_NEAR(rpart(A), rpart(B),tol); \
EXPECT_NEAR(dpart(A), dpart(B),tol)
/// Simple taylor series, truncated when |S| is "small enough"
template <class DerivedA, typename ReturnT = typename DerivedA::PlainObject>
ReturnT
expm4(const Eigen::EigenBase<DerivedA> & A_,
typename DerivedA::RealScalar mn = std::numeric_limits<typename DerivedA::RealScalar>::epsilon() * 1000)
{
//std::cerr << "do PO:" << type_name<typename DerivedA::PlainObject>() << "\n";
typedef typename DerivedA::RealScalar Real;
using std::isfinite;
const DerivedA & A = A_.derived();
int maxt = std::numeric_limits<Real>::digits;
int s = log2(rpart(A.derived().norm())) + 1;
s = std::max(0, s);
auto B = A * pow(Real(2), -s);
ReturnT R(A.rows(), A.cols());
R.setIdentity();
R += B;
ReturnT S = B;
for (int ii = 2; ii < maxt; ii++) {
S = S * B * Real(1.0/ii);
R += S;
auto Sn = S.norm();
if (!isfinite(Sn)) {
std::cout << "expm() non-finite norm:" << Sn << " at " << ii << "\n";
std::cout << " |R| = " << R.norm() << " s=" << s << "\n"
<< " |A| = " << rpart(A.real().norm()) << "\n"
<< " |A/2^s|=" << rpart(A.real().norm()/pow(2,s)) << "\n";
break;
}
// converged yet?
if (Sn < mn)
break;
if (ii == maxt - 1) {
std::cout << "expm() didn't converge in " << maxt << " |S| = " << Sn << "\n";
throw std::invalid_argument("no converge");
}
}
for (; s; s--)
R = R * R;
return R;
}
template <class T, int NN = 30, class DT = dual<T> >
void dexpm() {
//typedef std::complex<float> T;
//typedef std::complex<dual<T>> dualt;
auto tol = NN * NN * 10000 * Eigen::NumTraits<T>::epsilon();
#define N2 2*NN
// check dual
emtx<T,NN> A = emtx<T,NN>::Random();
emtx<T,NN> V = emtx<T,NN>::Random();
emtx<T,NN> dA1,dA2,dA3,eA1,eA2,eA3;
// dA/dV method 1
emtx<T,N2> AVA = emtx<T,N2>::Zero();
AVA.block( 0, 0,NN,NN) = A;
AVA.block( 0,NN,NN,NN) = V;
AVA.block(NN,NN,NN,NN) = A;
AVA = AVA.exp();
eA1 = AVA.block(0,0,NN,NN);
dA1 = AVA.block(0,NN,NN,NN);
// dA/dV method 2
emtx<DT, NN> a,b;
a = A + DT(1_e) * V;
b = eexpokit::padm(a,13);
//b = expm4(a);
//b = a.exp();
eA2 = rpart(b);
dA2 = dpart(b);
#if 0
// dA/dV method 3
//typedef Eigen::AutoDiffScalar<emtx<T,NN>> AD;
typedef Eigen::Matrix<T,1,1> Vector1t;
typedef Eigen::AutoDiffScalar<Vector1t> AD;
typedef Eigen::Matrix<AD,NN,NN> MatrixAD;
//MatrixAD c = A.template cast<AD>();
MatrixAD c(A);
for (Eigen::Index j = 0; j < NN; j++)
for (Eigen::Index i = 0; i < NN; i++)
c(i,j).derivatives()(0) = V(i,j);
//auto d = eexpokit::padm(c,8);
MatrixAD d = c.exp();
eA3 = d;
for (Eigen::Index j = 0; j < NN; j++)
for (Eigen::Index i = 0; i < NN; i++)
dA3(i,j) = d(i,j).derivatives()(0);
EXPECT_LT((dA1 - dA3).norm(), tol) << "dA1=" << dA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "dA3=" << dA3.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
#endif
#if 0
std::cout << "A=" << A << "\n";
std::cout << "V=" << V << "\n";
std::cout << "a=" << a << "\n";
std::cout << "b=" << b << "\n";
#endif
EXPECT_LT((eA1 - eA2).norm(), tol) << "eA1=" << eA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "eA2=" << eA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
EXPECT_LT((dA1 - dA2).norm(), tol) << "dA1=" << dA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "dA2=" << dA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
#undef NN
#undef N2
}
#if defined(PHASE_1)
TEST(dexpm, float2) { dexpm<float,2>(); }
//TEST(dexpm, float3) { dexpm<float,3>(); }
TEST(dexpm, float7) { dexpm<float,7>(); }
#elif defined(PHASE_2)
TEST(dexpm, float8) { dexpm<float,8>(); }
//TEST(dexpm, float16) { dexpm<float,16>(); }
TEST(dexpm, float31) { dexpm<float,31>(); }
#elif defined(PHASE_3)
TEST(dexpm, double2) { dexpm<double,2>(); }
TEST(dexpm, double3) { dexpm<double,3>(); }
#elif defined(PHASE_4)
TEST(dexpm, double4) { dexpm<double,4>(); }
TEST(dexpm, double31) { dexpm<double,31>(); }
//TEST(dexpm, adouble) { dexpm<double, adouble>(); }
#elif defined(PHASE_5)
TEST(dexpm, cfloat8) { dexpm<complexf,8,cdualf>(); }
TEST(dexpm, cfloat31) { dexpm<complexf,31,cdualf>(); }
#endif
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char **argv)
{
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

213
src/include/cppduals/tests/test_fmt.cpp

@ -0,0 +1,213 @@
//===-- test_dual.cpp - test duals/dual -------------------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_dual Dual number libfmt formatting tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include <fmt/format.h>
#define CPPDUALS_LIBFMT
#define CPPDUALS_LIBFMT_COMPLEX
#include <duals/dual>
#include "gtest/gtest.h"
using duals::dualf;
using duals::duald;
using duals::dualld;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
using namespace duals::literals;
using namespace std::complex_literals;
TEST(libfmt, complex_) {
std::string s = fmt::format("{}", 2.f + 3if);
EXPECT_EQ(s, "(2.0+3.0if)");
}
TEST(libfmt, complex_el) {
std::string s = fmt::format("{}", 2.l + 3il);
EXPECT_EQ(s, "(2.0+3.0il)");
}
TEST(libfmt, complex_flags) {
std::string s;
s = fmt::format("{}", 2. + 3i);
EXPECT_EQ(s, "(2.0+3.0i)");
s = fmt::format("{:$}", 2. + 3i);
EXPECT_EQ(s, "(2.0+3.0i)");
s = fmt::format("{:*}", 2. + 3i);
EXPECT_EQ(s, "(2.0+3.0*i)");
s = fmt::format("{:,}", 2. + 3i);
EXPECT_EQ(s, "(2.0,3.0)");
// + +
s = fmt::format("{:$+}", 2. + 3i);
EXPECT_EQ(s, "(+2.0+3.0i)");
s = fmt::format("{:*+}", 2. + 3i);
EXPECT_EQ(s, "(+2.0+3.0*i)");
s = fmt::format("{:,+}", 2. + 3i);
EXPECT_EQ(s, "(+2.0,+3.0)");
// + -
s = fmt::format("{:$+}", 2. - 3i);
EXPECT_EQ(s, "(+2.0-3.0i)");
s = fmt::format("{:*+}", 2. - 3i);
EXPECT_EQ(s, "(+2.0-3.0*i)");
s = fmt::format("{:,+}", 2. - 3i);
EXPECT_EQ(s, "(+2.0,-3.0)");
}
TEST(libfmt, complex_all_real) {
std::string s;
s = fmt::format("{}", 2. + 0i);
EXPECT_EQ(s, "(2.0)");
s = fmt::format("{:*}", 2. + 0i);
EXPECT_EQ(s, "(2.0)");
s = fmt::format("{:,}", 2. + 0i);
EXPECT_EQ(s, "(2.0,0.0)");
}
TEST(libfmt, complex_all_imag) {
std::string s;
s = fmt::format("{}", 0. + 3i);
EXPECT_EQ(s, "(3.0i)");
s = fmt::format("{:*}", 0. + 3i);
EXPECT_EQ(s, "(3.0*i)");
s = fmt::format("{:,}", 0. + 3i);
EXPECT_EQ(s, "(0.0,3.0)");
}
TEST(libfmt, complex_plus) {
std::string s = fmt::format("{:+}", 1. + 3i);
EXPECT_EQ(s, "(+1.0+3.0i)");
s = fmt::format("{:+}", 1. - 3i);
EXPECT_EQ(s, "(+1.0-3.0i)");
}
TEST(libfmt, complex_g) {
std::string s = fmt::format("{:g}", 2.f + 3if);
EXPECT_EQ(s, "(2+3if)");
}
TEST(libfmt, complex_gs) {
std::string s = fmt::format("{:*g}", 3i);
EXPECT_EQ(s, "(3*i)");
}
TEST(libfmt, complex_gel) {
std::string s = fmt::format("{:g}", 2.l + 3il);
EXPECT_EQ(s, "(2+3il)");
}
TEST(libfmt, dual_) {
std::string s = fmt::format("{}", 2 + 3_ef);
EXPECT_EQ(s, "(2.0+3.0_ef)");
}
TEST(libfmt, dual_el) {
std::string s = fmt::format("{}", 2 + 3_el);
EXPECT_EQ(s, "(2.0+3.0_el)");
}
TEST(libfmt, dual_flags) {
std::string s;
s = fmt::format("{}", 2. + 3_e);
EXPECT_EQ(s, "(2.0+3.0_e)");
s = fmt::format("{:$}", 2. + 3_e);
EXPECT_EQ(s, "(2.0+3.0_e)");
s = fmt::format("{:*}", 2. + 3_e);
EXPECT_EQ(s, "(2.0+3.0*e)");
s = fmt::format("{:,}", 2. + 3_e);
EXPECT_EQ(s, "(2.0,3.0)");
// + +
s = fmt::format("{:$+}", 2. + 3_e);
EXPECT_EQ(s, "(+2.0+3.0_e)");
s = fmt::format("{:*+}", 2. + 3_e);
EXPECT_EQ(s, "(+2.0+3.0*e)");
s = fmt::format("{:,+}", 2. + 3_e);
EXPECT_EQ(s, "(+2.0,+3.0)");
// + -
s = fmt::format("{:$+}", 2. - 3_e);
EXPECT_EQ(s, "(+2.0-3.0_e)");
s = fmt::format("{:*+}", 2. - 3_e);
EXPECT_EQ(s, "(+2.0-3.0*e)");
s = fmt::format("{:,+}", 2. - 3_e);
EXPECT_EQ(s, "(+2.0,-3.0)");
}
TEST(libfmt, dual_all_real) {
std::string s;
s = fmt::format("{}", 2 + 0_e);
EXPECT_EQ(s, "(2.0)");
s = fmt::format("{:*}", 2 + 0_e);
EXPECT_EQ(s, "(2.0)");
s = fmt::format("{:,}", 2 + 0_e);
EXPECT_EQ(s, "(2.0,0.0)");
}
TEST(libfmt, dual_all_dual) {
std::string s;
s = fmt::format("a{}b", 0 + 3_e);
EXPECT_EQ(s, "a(3.0_e)b");
s = fmt::format("a{:*}b", 0 + 3_e);
EXPECT_EQ(s, "a(3.0*e)b");
s = fmt::format("a{:,}b", 0 + 3_e);
EXPECT_EQ(s, "a(0.0,3.0)b");
}
TEST(libfmt, dual_g) {
std::string s = fmt::format("{:g}", 2 + 3_ef);
EXPECT_EQ(s, "(2+3_ef)");
}
TEST(libfmt, dual_gs) {
std::string s = fmt::format("a{:*g}b", 3_e);
EXPECT_EQ(s, "a(3*e)b");
s = fmt::format("{:*+g}", 3_e);
EXPECT_EQ(s, "(+3*e)");
}
TEST(libfmt, dual_gel) {
std::string s = fmt::format("{:g}", 2 + 3_el);
EXPECT_EQ(s, "(2+3_el)");
}
TEST(libfmt, dual_cgt) {
std::string s = fmt::format("{:g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)");
}
TEST(libfmt, dual_cgts) {
std::string s;
s = fmt::format("{:**g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2+3*ef)+(4+5*ef)*i)"); // todo - should be *if
s = fmt::format("{:,*g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2+3*ef),(4+5*ef))");
s = fmt::format("{:,,g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2,3),(4,5))");
}

215
src/include/cppduals/tests/test_funcs.cpp

@ -0,0 +1,215 @@
//===-- test_funcs.cpp - test duals/dual ------------------------*- C++ -*-===//
//
// Part of the cppduals Project
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
#include "gtest/gtest.h"
#include <duals/dual>
#include <complex>
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<float> complexf;
typedef std::complex<double> complexd;
//using std::complex;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ asdf; EXPECT_TRUE(asdf::value); }
#define EXPECT_CNEAR(a,b,prec) EXPECT_NEAR(std::abs((a) - (b)), 0, std::abs(prec))
// rough comparison of a finite-differences approx of the derivative
// with the duals's implementation. just meant to catch wild wrongness,
// not verify precision.
#define FD_CHECK(T, F, ...) \
TEST(func##_##T, F) { \
for (T x : __VA_ARGS__) { \
T prec = 100 * std::sqrt(std::numeric_limits<T>::epsilon()); \
T dd = dpart(F(x + dual<T>(0,1))); \
/*T dx = std::numeric_limits<T>::epsilon() * (T)1000000; */ \
T dx = T(1)/ (1ull << (std::numeric_limits<T>::digits / 3)); \
T fd = (F(x + dx) - F(x - dx)) / (2*dx); \
EXPECT_CNEAR(dd, fd, prec * std::abs(std::max(std::max(dd,fd),T(1)))) \
<< "dd=" << dd << " fd=" << fd << " x=" << x << " dx=" << dx; \
} \
}
FD_CHECK(double, exp, {-1,0,1})
FD_CHECK(double, log, {1})
//FD_CHECK(complexd, log, {-1,1}) TODO
FD_CHECK(double, log10, {1})
//FD_CHECK(complexd, log10, {-1,0,1}) TODO
FD_CHECK(double, sqrt, {0.5,1.0})
FD_CHECK(double, cbrt, {-10.,-0.01,0.01,1.0,10.})
//FD_CHECK(complexd, sqrt, {0,1}) TODO
FD_CHECK(double, sin, {-1,0,1})
FD_CHECK(double, cos, {-1,0,1})
FD_CHECK(double, tan, {-1,0,1})
FD_CHECK(double, asin, {-.9,0.,.9})
FD_CHECK(double, acos, {-.9,0.,.9})
FD_CHECK(double, atan, {-10,-1,0,1,10})
// TODO:
//FD_CHECK(double, sinh, {0})
//FD_CHECK(double, cosh, {0})
//FD_CHECK(double, tanh, {0})
//FD_CHECK(double, asinh, {0})
//FD_CHECK(double, acosh, {0})
//FD_CHECK(double, atanh, {0})
FD_CHECK(double, erf, {-1,0,1})
FD_CHECK(double, erfc, {-1,0,1})
FD_CHECK(double, tgamma, {1.,0.5,10.})
FD_CHECK(double, lgamma, {-1.1, 0.5, 1.1, 2.})
// check that functions with poles in their derivatives dont generate
// NaNs at the poles if dpart==0.
#define DZERO_CHECK(F, DZ) \
TEST(zero_##F, DZ) { \
dual<double> d(DZ,0); \
EXPECT_TRUE(std::isfinite(F(d).dpart())); \
}
DZERO_CHECK(log, 0)
DZERO_CHECK(sqrt, 0)
DZERO_CHECK(cbrt, 0)
DZERO_CHECK(asin, 1)
DZERO_CHECK(acos, 1)
//DZERO_CHECK(atan, i)
//DZERO_CHECK(atan2, i)
// These dont really cause d/dt = 0, but do a partial check and
// increase code coverage.
DZERO_CHECK(tgamma, 0)
DZERO_CHECK(lgamma, 0)
TEST(func, tgamma) {
duald x = 10 + 4_e;
//EXPECT_EQ(tgamma(x).rpart(), 362880); "interestingly", compiling without optimization (-O0) causes this to fail
EXPECT_NEAR(tgamma(x).rpart(), 362880, 362880 * 100 * std::numeric_limits<double>::epsilon());
}
TEST(func, rpart) {
dualf x = 10 + 4_e;
EXPECT_EQ(rpart(x), 10);
}
TEST(func, dpart) {
dualf x = 2 + 4_e;
EXPECT_EQ(dpart(x), 4);
}
TEST(func, abs) {
}
TEST(func, arg) {
}
TEST(func, norm) {
}
TEST(func, conj) {
}
TEST(func, polar) {
}
struct pike_f1 {
// function
template <typename TYPE>
TYPE
f(const TYPE & x) {
return exp(x) / sqrt(pow(sin(x), 3) + pow(cos(x), 3));
}
// analytic derivative
template <typename TYPE>
TYPE
df(const TYPE & x) {
return (exp(x) * (3 * cos(x) + 5*cos(3*x) + 9 * sin(x) + sin(3*x))) /
(8 * pow(pow(sin(x), (3)) + pow(cos(x), 3), 3./2.));
}
// analytic second derivative
template <typename TYPE>
TYPE
ddf(const TYPE & x) {
return (exp(x) * (130 - 12 * cos(2*x) + 30*cos(4*x)
+ 12*cos(6*x)
- 111.*sin(2*x) + 48.*sin(4*x) + 5*sin(6*x))) /
(64. * pow(pow(sin(x), 3) + pow(cos(x), 3), 5./2.));
}
// analytic third derivative
template <typename TYPE>
TYPE
dddf(const TYPE & x) {
return exp(x)*(1.0)
/ pow(sin(x)
+ pow(cos(x),(3.0))
- pow(cos(x),(2.0)) * sin(x), 7.0/2.0)
* (cos(x) *
- (186.0)
+ sin(x)*(68.0)
+ pow(cos(x),3)*171
- pow(cos(x),5)*42
- pow(cos(x),7)*33
+ pow(cos(x),9)*110
+ pow(cos(x),2)*sin(x)*(256.0)
- pow(cos(x),4)*sin(x)*(495.0)
+ pow(cos(x),6)*sin(x)*(139.0)
+ pow(cos(x),8)*sin(x)*74.0) * (1.0/8);
}
};
TEST(diff, pike) {
#if 1
typedef double real_t;
typedef duald dual_t;
typedef hyperduald hdual_t;
#else
typedef float real_t;
typedef dualf dual_t;
typedef hyperduald hdual_t;
#endif
pike_f1 f1;
// calculate f, f' and f'' and f''' analytically at x
real_t x = 7;
real_t f = f1.f(x);
real_t fp = f1.df(x);
real_t fpp = f1.ddf(x);
real_t fppp = f1.dddf(x);
// calculate f, f' and f'' and f'' and f''' using duals
dual_t dfp = f1.f(x + 1_e);
dual_t ddfp = f1.df(x + 1_e);
real_t x4 = 0;
hdual_t dfpp = f1.f(hdual_t(x+1_e, 1 + x4*1_e) ); // x + 1*e1 + 1*e2 + x4*e1e2
hdual_t dfppp = f1.df(hdual_t(x+1_e, 1 + x4*1_e));
real_t prec = std::numeric_limits<real_t>::epsilon() * 1e6;
//prec = 1e-11;
EXPECT_NEAR(f, dfpp.rpart().rpart(), prec);
EXPECT_NEAR(fp, dfp.dpart(), prec);
EXPECT_NEAR(fp, ddfp.rpart(), prec);
EXPECT_NEAR(fp, dfpp.rpart().dpart(), prec);
EXPECT_NEAR(fpp, ddfp.dpart(), prec);
EXPECT_NEAR(fpp, dfpp.dpart().dpart(), prec);
EXPECT_NEAR(fppp, dfppp.dpart().dpart(), prec);
//std::cout << "dfpp=" << dfpp << "\n";
//std::cout << "dfppp=" << dfppp << "\n";
}
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char **argv)
{
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

402
src/include/cppduals/tests/test_packets.cpp

@ -0,0 +1,402 @@
//===-- test_packets.cpp - test duals/dual_eigen -----------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_packets Dual number Eigen integration tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include "gtest/gtest.h"
using duals::rpart;
using duals::dpart;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int K = N> using ecf = Eigen::Matrix<complexf, N, K> ;
template <int N=2, int K = N> using edf = Eigen::Matrix<dualf, N, K> ;
template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); }
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B))
#define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B))
#define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B))
#define EXPECT_DNEAR(A,B,tol) \
EXPECT_NEAR(abs(rpart((A) - (B))),0,tol); \
EXPECT_NEAR(abs(dpart((A) - (B))),0,tol)
#if !defined(CPPDUALS_DONT_VECTORIZE) && !defined(EIGEN_DONT_VECTORIZE)
TEST(Packet1cdf, pload_pstore) {
using namespace Eigen::internal;
cdualf cd1 = cdualf(1+2_ef,3+4_ef);
cdualf cd2 = cdualf(5+6_ef,7+8_ef);
Packet1cdf p1 = pload<Packet1cdf>(&cd1);
pstore(&cd2, p1);
EXPECT_DEQ(cd1, cd2);
}
using duals::randos::random2;
#define GEN_PACKET_TEST_BI(PTYPE,pop,op) TEST(PTYPE,pop) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
double tol = rpart(20*Eigen::NumTraits<DTYPE>::epsilon()); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd3(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
cd2[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
PTYPE p2 = pload<PTYPE>(cd2.data()); \
auto p3 = pop (p1, p2); \
pstore(cd3.data(), p3); \
for (int i = 0; i < N; i++) { \
EXPECT_DNEAR(cd3[i], cd1[i] op cd2[i], tol) \
<< cd1[i] << ',' << cd2[i] << " fail at " << i; \
} \
}
#define GEN_PACKET_TEST_UN(PTYPE,pop,op) TEST(PTYPE,pop) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
double tol = rpart(20*Eigen::NumTraits<DTYPE>::epsilon()); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
auto p2 = pop (p1); \
pstore(cd2.data(), p2); \
for (int i = 0; i < N; i++) { \
EXPECT_DNEAR(cd2[i], op(cd1[i]), tol) \
<< cd1[i] << " fail at " << i; \
} \
}
#define GEN_PACKET_TEST_RD(PTYPE,pop,op) TEST(PTYPE,pop) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
double tol = rpart(20*Eigen::NumTraits<DTYPE>::epsilon()); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
DTYPE p2 = pop (p1); \
DTYPE acc(1); \
for (int i = 0; i < N; i++) \
acc op##= cd1[i]; \
EXPECT_DNEAR(acc, (DTYPE(1) op p2), tol) \
<< acc << " " << p2 << " fail."; \
}
#define GEN_PACKET_TEST_REVERSE(PTYPE) TEST(PTYPE,preverse) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
PTYPE p2 = preverse (p1); \
pstore(cd2.data(), p2); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[i], cd2[N-1-i]) \
<< cd1[i] << "," << cd2[N-1-i] << " @ " << i << " fail."; \
} \
}
#define GEN_PACKET_TEST_FIRST(PTYPE) TEST(PTYPE,pfirst) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
DTYPE c2 = pfirst (p1); \
EXPECT_DEQ(cd1[0], c2) \
<< cd1[0] << "," << c2 << " fail."; \
}
#define GEN_PACKET_TEST_SET1(PTYPE) TEST(PTYPE,pset1) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
cd2[i] = random2<DTYPE>(); \
} \
DTYPE c2 = random2<DTYPE>(); \
PTYPE p1 = pset1<PTYPE>(c2); \
PTYPE p2 = pload1<PTYPE>(&c2); \
pstore(cd1.data(), p1); \
pstore(cd2.data(), p2); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[i], c2) \
<< i << ":" << cd1[i] << "," << c2 << " fail."; \
EXPECT_DEQ(cd2[i], c2) \
<< i << ":" << cd1[i] << "," << c2 << " fail."; \
} \
}
#define GEN_PACKET_TEST_LOADDUP(PTYPE) TEST(PTYPE,ploaddup) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(1+N/2); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < 1+N/2; i++) { cd1[i] = random2<DTYPE>(); } \
for (size_t i = 0; i < N ; i++) { cd2[i] = random2<DTYPE>(); } \
PTYPE p1 = ploaddup<PTYPE>(cd1.data()); \
pstore(cd2.data(), p1); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[i/2], cd2[i]) \
<< i << ":" << cd1[i/2] << "," << cd2[i] << " fail."; \
} \
}
#define GEN_PACKET_TEST_ULOAD(PTYPE) TEST(PTYPE,ploadu) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
char b1[sizeof(DTYPE) * (N+2)]; \
char b2[sizeof(DTYPE) * (N+2)]; \
DTYPE * cd1 = (DTYPE *)&b1[1]; \
DTYPE * cd2 = (DTYPE *)&b2[2]; \
for (size_t i = 0; i < N+1; i++) { \
cd1[i] = random2<DTYPE>(); \
cd2[i] = random2<DTYPE>(); \
} \
PTYPE p1 = ploadu<PTYPE>(&cd1[1]); \
pstoreu(&cd2[1], p1); \
for (int i = 1; i < N+1; i++) { \
EXPECT_DEQ(cd1[i], cd2[i]) \
<< cd1[i] << "," << cd2[i] << " fail."; \
} \
}
#define GEN_PACKET_TEST_BROADCAST(PTYPE,B) TEST(PTYPE,pbroadcast##B) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
PTYPE p1; \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(B); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < N; i++) { cd1[i] = random2<DTYPE>(); } \
PTYPE p0,p3,p2; \
if (B == 2) pbroadcast2(cd1.data(), p0,p1); \
if (B == 4) pbroadcast4(cd1.data(), p0,p1,p2,p3); \
pstore(cd2.data(), p0); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[0], cd2[i]) << i << ":" << cd1[0] << "," << cd2[i] << " fail."; \
} \
pstore(cd2.data(), p1); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[1], cd2[i]) << i << ":" << cd1[1] << "," << cd2[i] << " fail."; \
} \
if (B == 4) { \
pstore(cd2.data(), p2); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[2], cd2[i]) << i << ":" << cd1[2] << "," << cd2[i] << " fail."; \
} \
pstore(cd2.data(), p3); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(cd1[3], cd2[i]) << i << ":" << cd1[3] << "," << cd2[i] << " fail."; \
} \
} \
}
#define GEN_PACKET_TEST_CPLXFLIP(PTYPE) TEST(PTYPE,pcplxflip) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
cd2[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
PTYPE p2 = pcplxflip (p1); \
pstore(cd2.data(), p2); \
for (int i = 0; i < N; i++) { \
EXPECT_DEQ(real(cd1[i]), imag(cd2[i])) \
<< cd1[i] << "," << cd2[i] << " fail."; \
EXPECT_DEQ(imag(cd1[i]), real(cd2[i])) \
<< cd1[i] << "," << cd2[i] << " fail."; \
} \
}
#define GEN_PACKET_TEST_CONJ_HELPER(PTYPE) TEST(PTYPE,conj_helper) { \
using namespace Eigen::internal; \
typedef unpacket_traits<PTYPE>::type DTYPE; \
const static int N = unpacket_traits<PTYPE>::size; \
double tol = rpart(10*Eigen::NumTraits<DTYPE>::epsilon()); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd1(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd2(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> cd3(N); \
std::vector<DTYPE,Eigen::aligned_allocator<DTYPE>> r(N); \
for (size_t i = 0; i < N; i++) { \
cd1[i] = random2<DTYPE>(); \
cd2[i] = random2<DTYPE>(); \
cd3[i] = random2<DTYPE>(); \
} \
PTYPE p1 = pload<PTYPE>(cd1.data()); \
PTYPE p2 = pload<PTYPE>(cd2.data()); \
PTYPE p3 = pload<PTYPE>(cd3.data()); \
conj_helper<PTYPE,PTYPE,false,false> cj; p3 = cj.pmadd(p1,p2,p3); \
pstore(r.data(), p3); \
for (int i = 0; i < N; i++) { \
EXPECT_DNEAR(r[i], cd1[i] * cd2[i] + cd3[i], tol) \
<< r[i] << "!=" << cd1[i] << "*" << cd3[i] << "+" << cd3[i] << " fail."; \
} \
}
#define GEN_PACKET_TESTS(PTYPE) \
GEN_PACKET_TEST_BI(PTYPE,padd,+) \
GEN_PACKET_TEST_BI(PTYPE,psub,-) \
GEN_PACKET_TEST_BI(PTYPE,pmul,*) \
GEN_PACKET_TEST_BI(PTYPE,pdiv,/) \
GEN_PACKET_TEST_UN(PTYPE,pnegate,-) \
GEN_PACKET_TEST_RD(PTYPE,predux,+) \
GEN_PACKET_TEST_RD(PTYPE,predux_mul,*) \
GEN_PACKET_TEST_ULOAD(PTYPE) \
GEN_PACKET_TEST_SET1(PTYPE) \
GEN_PACKET_TEST_LOADDUP(PTYPE) \
/*GEN_PACKET_TEST_BROADCAST(PTYPE,2)*/ \
GEN_PACKET_TEST_BROADCAST(PTYPE,4) \
GEN_PACKET_TEST_FIRST(PTYPE) \
GEN_PACKET_TEST_REVERSE(PTYPE)
#define GEN_CPACKET_TESTS(PTYPE) \
GEN_PACKET_TESTS(PTYPE) \
GEN_PACKET_TEST_CPLXFLIP(PTYPE) \
GEN_PACKET_TEST_CONJ_HELPER(PTYPE) \
GEN_PACKET_TEST_UN(PTYPE,pconj,conj)
// TODO:
//pcplxflip
//preduxp
//pand
//por
//pxor
//andnot
//pbroadcast4
//ploadquad (for packets w/ size==8)
//pgather
//pscatter
//align_impl
//insertfirst
//insertlast
// test the tests
GEN_PACKET_TESTS(Packet4f)
GEN_CPACKET_TESTS(Packet2cf)
#if defined(EIGEN_VECTORIZE_AVX)
GEN_CPACKET_TESTS(Packet4cf)
#endif
#ifdef EIGEN_VECTORIZE_SSE
GEN_PACKET_TESTS(Packet2df)
GEN_PACKET_TESTS(Packet1dd)
GEN_CPACKET_TESTS(Packet1cdf)
#endif
#if defined(EIGEN_VECTORIZE_AVX)
GEN_PACKET_TESTS(Packet4df)
GEN_PACKET_TESTS(Packet2dd)
GEN_CPACKET_TESTS(Packet2cdf)
#if defined(__AVX2__)
GEN_CPACKET_TESTS(Packet1cdd)
#endif
#endif
#endif // CPPDUALS_DONT_VECTORIZE
TEST(compile, VECTORIZE) {
#if defined(CPPDUALS_DONT_VECTORIZE) || defined(EIGEN_DONT_VECTORIZE)
EXPECT_TRUE(false) << "CPPDUALS_DONT_VECTORIZE supresses vectorization tests!";
#endif
}
TEST(compile, SSE) {
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("SSE") != std::string::npos)
<< "Not using SSE instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_SSE
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse();
#endif
}
TEST(compile, AVX) {
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("AVX") != std::string::npos)
<< "Not using AVX instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_AVX
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse();
#endif
}
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char **argv)
{
std::ptrdiff_t l1, l2, l3;
Eigen::internal::manage_caching_sizes(Eigen::GetAction, &l1, &l2, &l3);
std::cout << "l1=" << l1 << " l2=" << l2 << " l3=" << l3 << "\n";
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

119
src/include/cppduals/tests/test_solve.cpp

@ -0,0 +1,119 @@
//===-- test_funcs.cpp - test duals/dual ------------------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_eigen Dual number Eigen integration tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include <unsupported/Eigen/MatrixFunctions>
#include <unsupported/Eigen/AutoDiff>
#include "eexpokit/padm.hpp"
#include "gtest/gtest.h"
using duals::rpart;
using duals::dpart;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int K = N> using ecf = Eigen::Matrix<complexf, N, K> ;
template <int N=2, int K = N> using edf = Eigen::Matrix<dualf, N, K> ;
template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); }
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B))
#define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B))
#define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B))
#define EXPECT_DNEAR(A,B,tol) \
EXPECT_NEAR(rpart(A), rpart(B),tol); \
EXPECT_NEAR(dpart(A), dpart(B),tol)
template <class T, int NN = 30, class DT = dual<T> >
void solveLu() {
auto tol = NN * NN * 10000 * Eigen::NumTraits<T>::epsilon();
// check scalar
emtx<T,NN> a = emtx<T,NN>::Random();
emtx<T,NN> b = emtx<T,NN>::Random();
emtx<T,NN> c,d,e;
c = a * b;
d = a.lu().solve(c);
EXPECT_LT((b - d).norm(), tol);
// check dual
emtx<DT,NN> A = a + DT(0,1) * emtx<T,NN>::Random();
emtx<DT,NN> B = b + DT(0,1) * emtx<T,NN>::Random();
emtx<DT,NN> C,D,E;
C = A * B;
D = A.lu().solve(C);
EXPECT_LT(rpart(B - D).norm(), tol);
EXPECT_LT(dpart(B - D).norm(), tol);
}
#if defined(PHASE_1)
TEST(solveLu, float2) { solveLu<float,2>(); }
TEST(solveLu, float7) { solveLu<float,7>(); }
TEST(solveLu, float8) { solveLu<float,8>(); }
TEST(solveLu, float31) { solveLu<float,31>(); }
TEST(solveLu, double2) { solveLu<double,2>(); }
TEST(solveLu, double3) { solveLu<double,3>(); }
TEST(solveLu, double4) { solveLu<double,4>(); }
TEST(solveLu, double31) { solveLu<double,31>(); }
#elif defined(PHASE_2)
TEST(solveLu, complexf2) { solveLu<complexf,2,cdualf>(); }
TEST(solveLu, complexf8) { solveLu<complexf,8,cdualf>(); }
TEST(solveLu, complexf31) { solveLu<complexf,31,cdualf>(); }
TEST(solveLu, complexd31) { solveLu<complexd,31,cduald>(); }
#endif
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char **argv)
{
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

342
src/include/cppduals/tests/test_vectorize.cpp

@ -0,0 +1,342 @@
//===-- test_vectorize.cpp - test duals/dual_eigen -------------*- C++ -*-===//
//
// Part of the cppduals project.
// https://gitlab.com/tesch1/cppduals
//
// See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for
// license information.
//
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
/**
* \file test_vectorize Dual number Eigen vectorization op tests
*
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include "gtest/gtest.h"
using duals::rpart;
using duals::dpart;
using duals::dualf;
using duals::duald;
using duals::dualld;
using duals::hyperdualf;
using duals::hyperduald;
using duals::hyperdualld;
using duals::is_dual;
using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<dualf> cdualf;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
template <int N=2, int K = N> using ecf = Eigen::Matrix<complexf, N, K> ;
template <int N=2, int K = N> using edf = Eigen::Matrix<dualf, N, K> ;
template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); }
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B))
#define ASSERT_DNEAR(A,B,tol) \
ASSERT_NEAR(abs(rpart((A) - (B))),0,abs(rpart(A))*(tol)); \
ASSERT_NEAR(abs(dpart((A) - (B))),0,abs(dpart(A))*(tol))
#define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B))
#define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B))
#define EXPECT_DNEAR(A,B,tol) \
EXPECT_NEAR(abs(rpart((A) - (B))),0,abs(rpart(A))*(tol)); \
EXPECT_NEAR(abs(dpart((A) - (B))),0,abs(dpart(A))*(tol))
template <typename Rt>
void elemwise(int N) {
std::vector<Rt> a(N);
std::vector<Rt> b(N);
std::vector<Rt> cp(N);
std::vector<Rt> cm(N);
std::vector<Rt> ct(N);
std::vector<Rt> cd(N);
std::vector<Rt> cc(N);
std::vector<Rt> cca(N);
std::vector<Rt> ccb(N);
emtx<Rt> A(N,1);
emtx<Rt> B(N,1);
emtx<Rt> Cp(N,1);
emtx<Rt> Cm(N,1);
emtx<Rt> Ct(N,1);
emtx<Rt> Cd(N,1);
emtx<Rt> Cc(N,1);
emtx<Rt> Cca(N,1);
emtx<Rt> Ccb(N,1);
double tol = rpart(2000*Eigen::NumTraits<Rt>::epsilon());
using duals::randos::random2;
Rt sum(0);
for (int i = 0; i < N; i++) {
A(i) = a[i] = random2<Rt>();
B(i) = b[i] = random2<Rt>();
cp[i] = a[i] + b[i];
cm[i] = a[i] - b[i];
ct[i] = a[i] * b[i];
cd[i] = a[i] / b[i];
cc[i] = conj(a[i]) + conj(b[i]);
cca[i] = conj(a[i]) + b[i];
ccb[i] = a[i] + conj(b[i]);
sum += a[i];
}
Cp = A.array() + B.array();
Cm = A.array() - B.array();
Ct = A.array() * B.array();
Cd = A.array() / B.array();
Cc = conj(A.array()) + conj(B.array());
Cca = conj(A.array()) + B.array();
Ccb = A.array() + conj(B.array());
for (int i = 0; i < N; i++) {
ASSERT_DEQ(cp[i], Cp(i)) << "p mismatch at " << i << "\n";
ASSERT_DEQ(cm[i], Cm(i)) << "m mismatch at " << i << "\n";
ASSERT_DNEAR(ct[i], Ct(i),tol) << "t mismatch at " << i << "\n";
ASSERT_DNEAR(cd[i], Cd(i),3*tol) /* why is this so much worse? */
<< "d mismatch at " << i << " " << cd[i] << "|\n"
<< Cd(i) << " != " << a[i] << "/" << b[i] << "\n";
ASSERT_DEQ(cc[i], Cc(i)) << "c mismatch at " << i << "\n";
ASSERT_DEQ(cca[i], Cca(i)) << "ca mismatch at " << i << "\n";
ASSERT_DEQ(ccb[i], Ccb(i)) << "cb mismatch at " << i << "\n";
}
ASSERT_DNEAR(sum, A.sum(), N*tol);
ASSERT_DNEAR(sum, A.sum(), N*tol);
}
TEST(Vector, full_even_dualf) { elemwise<dualf>(512); }
TEST(Vector, full_even_duald) { elemwise<duald>(512); }
TEST(Vector, full_even_cdualf) { elemwise<cdualf>(512); }
TEST(Vector, full_odd_dualf) { elemwise<dualf>(2049); }
TEST(Vector, full_odd_duald) { elemwise<duald>(2049); }
TEST(Vector, full_odd_cdualf) { elemwise<cdualf>(2049); }
TEST(Vector, single_elem_dualf) { elemwise<dualf>(1); }
TEST(Vector, single_elem_duald) { elemwise<duald>(1); }
TEST(Vector, single_elem_cdualf) { elemwise<cdualf>(1); }
TEST(Vector, two_elem_dualf) { elemwise<dualf>(2); }
TEST(Vector, two_elem_duald) { elemwise<duald>(2); }
TEST(Vector, two_elem_cdualf) { elemwise<cdualf>(2); }
#define DBOUT(X)
#define MAKE_MULT_TEST(TYPE1, TYPE2, FIX, SIZE) \
TEST(MatMult, TYPE1##_##TYPE2##_##SIZE) { \
typedef TYPE1 T1; \
typedef TYPE2 T2; \
typedef decltype(TYPE1() * TYPE2()) T3; \
using duals::rpart; \
using duals::conj; \
/*using std::conj;*/ \
using duals::randos::random2; \
\
double tol = rpart(20*Eigen::NumTraits<T1>::epsilon()); \
static const Eigen::Index N = FIX; \
static const int n = SIZE; \
emtx<T1,N> A(n,n); \
emtx<T2,N> B(n,n); \
emtx<T3,N> C(n,n); \
emtx<T3,N> D(n,n); \
\
for (Eigen::Index i = 0; i < A.size(); i++) { \
A.data()[i] = random2<T1>(); \
B.data()[i] = random2<T2>(); \
} \
\
C.setZero(); \
for(int i=0; i<n; ++i) \
for(int j=0; j<n; ++j) \
for(int k=0; k<n; ++k) \
C.data()[j*n+i] += A.data()[k*n+i] * B.data()[j*n+k]; \
\
DBOUT(std::cerr << "--------------------------\n"); \
D = A*B; \
ASSERT_NEAR((double)rpart(D - C).norm(), 0, rpart(C).norm() * tol) << "r|a*b" << C << "\n" << D; \
ASSERT_NEAR((double)dpart(D - C).norm(), 0, dpart(C).norm() * tol) << "d|a*b" << C << "\n" << D; \
\
C.setZero(); \
for(int i=0; i<n; ++i) \
for(int j=0; j<n; ++j) \
for(int k=0; k<n; ++k) \
C.data()[j*n+i] += A.data()[k*n+i] * conj(B.data()[k*n+j]); \
\
DBOUT(std::cerr << CRED " a*b'" CRESET "\n"); \
D = A*B.adjoint(); \
ASSERT_NEAR((double)rpart(D - C).norm(), 0, rpart(C).norm() * tol) << "r|a*b'"; \
ASSERT_NEAR((double)dpart(D - C).norm(), 0, dpart(C).norm() * tol) << "d|a*b'"; \
\
C.setZero(); \
for(int i=0; i<n; ++i) \
for(int j=0; j<n; ++j) \
for(int k=0; k<n; ++k) \
C.data()[j*n+i] += conj(A.data()[i*n+k]) * B.data()[j*n+k]; \
\
DBOUT(std::cerr << CRED " a'*b" CRESET "\n"); \
D = A.adjoint()*B; \
ASSERT_NEAR((double)rpart(D - C).norm(), 0, rpart(C).norm() * tol) << "r|a'*b"; \
ASSERT_NEAR((double)dpart(D - C).norm(), 0, dpart(C).norm() * tol) << "d|a'*b"; \
\
C.setZero(); \
for(int i=0; i<n; ++i) \
for(int j=0; j<n; ++j) \
for(int k=0; k<n; ++k) \
C.data()[j*n+i] += A.data()[k*n+i] * (B.data()[k*n+j]); \
\
DBOUT(std::cerr << CRED " a*b.'" CRESET "\n"); \
D = A*B.transpose(); \
ASSERT_NEAR((double)rpart(D - C).norm(), 0, rpart(C).norm() * tol) << "r|a*b.'"; \
ASSERT_NEAR((double)dpart(D - C).norm(), 0, dpart(C).norm() * tol) << "d|a*b.'"; \
\
C.setZero(); \
for(int i=0; i<n; ++i) \
for(int j=0; j<n; ++j) \
for(int k=0; k<n; ++k) \
C.data()[j*n+i] += (A.data()[i*n+k]) * B.data()[j*n+k]; \
\
DBOUT(std::cerr << CRED " a.'*b'" CRESET "\n"); \
D = A.transpose()*B; \
ASSERT_NEAR((double)rpart(D - C).norm(), 0, rpart(C).norm() * tol) << "r|a.'*b"; \
ASSERT_NEAR((double)dpart(D - C).norm(), 0, dpart(C).norm() * tol) << "d|a.'*b"; \
\
C.setZero(); \
for(int i=0; i<n; ++i) \
for(int j=0; j<n; ++j) \
for(int k=0; k<n; ++k) \
C.data()[j*n+i] += conj(A.data()[i*n+k]) * conj(B.data()[k*n+j]); \
\
DBOUT(std::cerr << CRED " a'*b'" CRESET "\n"); \
D = A.adjoint()*B.adjoint(); \
ASSERT_NEAR((double)rpart(D - C).norm(), 0, rpart(C).norm() * tol) << "r|a'*b'"; \
ASSERT_NEAR((double)dpart(D - C).norm(), 0, dpart(C).norm() * tol) << "d|a'*b'"; \
}
#if defined(PHASE_1)
MAKE_MULT_TEST(double, double, 65, 65)
MAKE_MULT_TEST(complexf, complexf, 2, 2)
MAKE_MULT_TEST(complexf, complexf, 4, 4)
//MAKE_MULT_TEST(complexf, complexf, 8, 8)
MAKE_MULT_TEST(complexf, complexf, Eigen::Dynamic, 8)
MAKE_MULT_TEST(complexf, complexf, Eigen::Dynamic, 64)
//MAKE_MULT_TEST(complexf, complexf, Eigen::Dynamic, 129)
MAKE_MULT_TEST(complexd, complexd, Eigen::Dynamic, 129)
#elif defined(PHASE_2)
MAKE_MULT_TEST(double, double, 2, 2)
MAKE_MULT_TEST(complexf, float, 2, 2)
MAKE_MULT_TEST(float, complexf, 2, 2)
//MAKE_MULT_TEST(complexf, float, 4, 4)
//MAKE_MULT_TEST(float, complexf, 4, 4)
//MAKE_MULT_TEST(complexf, float, 24, 24)
//MAKE_MULT_TEST(float, complexf, 24, 24)
MAKE_MULT_TEST(complexf, float, Eigen::Dynamic, 31)
MAKE_MULT_TEST(float, complexf, Eigen::Dynamic, 31)
//MAKE_MULT_TEST(complexd, double, Eigen::Dynamic, 31)
//MAKE_MULT_TEST(double, complexd, Eigen::Dynamic, 31)
#elif defined(PHASE_3)
MAKE_MULT_TEST(dualf, dualf, 2, 2)
MAKE_MULT_TEST(dualf, dualf, 3, 3)
MAKE_MULT_TEST(dualf, dualf, 4, 4)
MAKE_MULT_TEST(dualf, dualf, 7, 7)
MAKE_MULT_TEST(dualf, dualf, 8, 8)
MAKE_MULT_TEST(dualf, dualf, 31, 31)
MAKE_MULT_TEST(dualf, dualf, Eigen::Dynamic, 127)
//MAKE_MULT_TEST(dualf, float, 31, 31)
//MAKE_MULT_TEST(float, dualf, 31, 31)
MAKE_MULT_TEST(cdualf, cdualf, 2,2)
MAKE_MULT_TEST(cdualf, cdualf, 3,3)
MAKE_MULT_TEST(cdualf, cdualf, 4,4)
MAKE_MULT_TEST(cdualf, cdualf, 31,31)
MAKE_MULT_TEST(cdualf, cdualf, Eigen::Dynamic, 127)
//MAKE_MULT_TEST(cdualf, cdualf, Eigen::Dynamic, 255)
#elif defined(PHASE_4)
MAKE_MULT_TEST(cdualf, dualf, 4,4)
MAKE_MULT_TEST(dualf, cdualf, 4,4)
MAKE_MULT_TEST(dualf, cdualf, 23,23)
MAKE_MULT_TEST(dualf, cdualf, Eigen::Dynamic,127)
MAKE_MULT_TEST(cdualf, dualf, 8,8)
MAKE_MULT_TEST(cdualf, dualf, Eigen::Dynamic,127)
#elif defined(PHASE_5)
MAKE_MULT_TEST(duald, duald, 2, 2)
MAKE_MULT_TEST(duald, duald, 3, 3)
MAKE_MULT_TEST(duald, duald, 4, 4)
MAKE_MULT_TEST(duald, duald, 31, 31)
MAKE_MULT_TEST(duald, duald, Eigen::Dynamic, 127)
//MAKE_MULT_TEST(duald, duald, Eigen::Dynamic, 255)
MAKE_MULT_TEST(cduald, duald, 4,4)
MAKE_MULT_TEST(duald, cduald, 4,4)
MAKE_MULT_TEST(cduald, cduald, Eigen::Dynamic, 127)
MAKE_MULT_TEST(duald, cduald, Eigen::Dynamic,127)
MAKE_MULT_TEST(cduald, duald, Eigen::Dynamic,127)
#endif
TEST(flags, VECTORIZE) {
#if defined(CPPDUALS_DONT_VECTORIZE) || defined(EIGEN_DONT_VECTORIZE)
EXPECT_TRUE(false) << "CPPDUALS_DONT_VECTORIZE supresses vectorization tests!";
#endif
}
TEST(flags, SSE) {
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("SSE") != std::string::npos)
<< "Not using SSE instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_SSE
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse();
#endif
}
TEST(flags, AVX) {
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("AVX") != std::string::npos)
<< "Not using AVX instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_AVX
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse();
#endif
}
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__
int main(int argc, char **argv)
{
std::ptrdiff_t l1, l2, l3;
Eigen::internal::manage_caching_sizes(Eigen::GetAction, &l1, &l2, &l3);
std::cout << "l1=" << l1 << " l2=" << l2 << " l3=" << l3 << "\n";
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";
::testing::InitGoogleTest(&argc, argv);
std::cout.precision(20);
std::cerr.precision(20);
return RUN_ALL_TESTS();
}

106
src/include/cppduals/tests/type_name.hpp

@ -0,0 +1,106 @@
// https://stackoverflow.com/questions/81870/is-it-possible-to-print-a-variables-type-in-standard-c
#pragma once
#include <cstddef>
#include <stdexcept>
#include <cstring>
#include <ostream>
#ifndef _MSC_VER
# if __cplusplus < 201103
# define CONSTEXPR11_TN
# define CONSTEXPR14_TN
# define NOEXCEPT_TN
# elif __cplusplus < 201402
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN
# define NOEXCEPT_TN noexcept
# else
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN constexpr
# define NOEXCEPT_TN noexcept
# endif
#else // _MSC_VER
# if _MSC_VER < 1900
# define CONSTEXPR11_TN
# define CONSTEXPR14_TN
# define NOEXCEPT_TN
# elif _MSC_VER < 2000
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN
# define NOEXCEPT_TN noexcept
# else
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN constexpr
# define NOEXCEPT_TN noexcept
# endif
#endif // _MSC_VER
class static_string
{
const char* const p_;
const std::size_t sz_;
public:
typedef const char* const_iterator;
template <std::size_t N>
CONSTEXPR11_TN static_string(const char(&a)[N]) NOEXCEPT_TN
: p_(a)
, sz_(N-1)
{}
CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN
: p_(p)
, sz_(N)
{}
//CONSTEXPR11_TN operator const char *() const { return p_; }
CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}
CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}
CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}
CONSTEXPR11_TN const_iterator end() const NOEXCEPT_TN {return p_ + sz_;}
CONSTEXPR11_TN char operator[](std::size_t n) const
{
return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
}
std::string str() const { return std::string(begin(), end()); }
};
inline
std::ostream&
operator<<(std::ostream& os, static_string const& s)
{
return os.write(s.data(), s.size());
}
#define CRED "\x1b[31m"
#define CGREEN "\x1b[32m"
#define CYELLOW "\x1b[33m"
#define CBLUE "\x1b[34m"
#define CMAGENTA "\x1b[35m"
#define CCYAN "\x1b[36m"
#define CRESET "\x1b[0m"
template <class T>
CONSTEXPR14_TN
static_string
type_name()
{
#ifdef __clang__
static_string p = __PRETTY_FUNCTION__;
return static_string(p.data() + 31, p.size() - 31 - 1);
#elif defined(__GNUC__)
static_string p = __PRETTY_FUNCTION__;
# if __cplusplus < 201402
return static_string(p.data() + 36, p.size() - 36 - 1);
# else
return static_string(p.data() + 46, p.size() - 46 - 1);
# endif
#elif defined(_MSC_VER)
static_string p = __FUNCSIG__;
return static_string(p.data() + 38, p.size() - 38 - 7);
#endif
}

17
src/include/cppduals/thirdparty/CMakeLists-gt.txt.in

@ -0,0 +1,17 @@
cmake_minimum_required (VERSION 2.8.2)
project (googletest-download NONE)
include (ExternalProject)
ExternalProject_Add (googletest
GIT_REPOSITORY https://github.com/google/googletest.git
# GIT_TAG master
GIT_TAG release-1.8.1
GIT_SHALLOW 1
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

220
src/include/cppduals/thirdparty/CMakeLists.txt

@ -0,0 +1,220 @@
# https://gist.github.com/johnb003/65982fdc7a1274fdb023b0c68664ebe4
# 3.10 adds support for "gtest_discover_tests" which enumerates the tests inside
# of the code and adds them to ctest.
#
cmake_minimum_required (VERSION 3.10)
project (cppduals_thirdparty)
include (ExternalProject)
get_directory_property (hasParent PARENT_DIRECTORY)
set (DEPS_ROOT "${CMAKE_BINARY_DIR}/root")
if (hasParent)
set (DEPS_ROOT "${CMAKE_BINARY_DIR}/thirdparty/root" PARENT_SCOPE)
endif (hasParent)
if (NOT WIN32)
set (DOWNLOAD_DIR "$ENV{HOME}/Downloads")
else (NOT WIN32)
set (DOWNLOAD_DIR "C:/Downloads")
endif (NOT WIN32)
#
# Google test (https://github.com/google/googletest/blob/master/googletest/README.md)
#
# Download and unpack googletest at configure time
configure_file (CMakeLists-gt.txt.in googletest-download/CMakeLists.txt)
execute_process (COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
if (result)
message (FATAL_ERROR "CMake step for googletest failed: ${result}")
endif ()
execute_process (COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
if (result)
message (FATAL_ERROR "Build step for googletest failed: ${result}")
endif ()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set (gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory (
${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories ("${gtest_SOURCE_DIR}/include")
endif ()
# Can simply link against gtest or gtest_main as needed. Eg
#add_executable (example example.cpp)
#target_link_libraries (example gtest_main)
#add_test (NAME example_test COMMAND example)
#
# Eigen
#
if (CPPDUALS_EIGEN_LATEST)
set (EIGEN_URL http://bitbucket.org/eigen/eigen/get/default.tar.bz2)
#set (EIGEN_MD5 ffc83130dcd37b694c6cf7e905099af9)
else ()
set (EIGEN_URL http://bitbucket.org/eigen/eigen/get/3.3.7.tar.bz2)
set (EIGEN_MD5 05b1f7511c93980c385ebe11bd3c93fa)
endif ()
ExternalProject_Add (eigenX
PREFIX eigenX
URL ${EIGEN_URL}
#URL_HASH MD5=${EIGEN_MD5}
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property (eigenX source_dir)
if (hasParent AND NOT EIGEN3_INCLUDE_DIRS)
set (EIGEN3_INCLUDE_DIRS "${source_dir}" PARENT_SCOPE)
endif ()
#
# Eigen-Expokit
#
set (EEX_SHA 72bf6e445d5ae84218dcbd74580720491e0074db )
ExternalProject_Add (expokitX
PREFIX expokitX
URL https://gitlab.com/api/v4/projects/tesch1%2Feigen-expokit/repository/archive.tbz2?sha=${EEX_SHA}
#URL_HASH MD5=96b79de1d01547f6d658865b7caa02ee
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property (expokitX source_dir)
if (hasParent)
set (EXPOKIT_INCLUDE_DIR "${source_dir}" PARENT_SCOPE)
endif()
#
# fmt
#
ExternalProject_Add (fmtX
PREFIX fmtX
URL https://github.com/fmtlib/fmt/archive/6.1.1.tar.gz
URL_HASH MD5=acfb83d44afdca171ee26c597c931e7c
DOWNLOAD_DIR ${DOWNLOAD_DIR}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property (fmtX source_dir)
ExternalProject_Get_Property (fmtX binary_dir)
if (hasParent)
message (" FMT3_INCLUDE_DIRS: ${source_dir}")
add_subdirectory (${source_dir} ${binary_dir} EXCLUDE_FROM_ALL)
endif ()
if (CPPDUALS_BENCHMARK)
#
# google benchmark
#
ExternalProject_Add (benchmarkX
PREFIX benchmarkX
URL "http://github.com/google/benchmark/archive/v1.5.0.tar.gz"
URL_HASH MD5=eb1466370f3ae31e74557baa29729e9e
DOWNLOAD_DIR ${DOWNLOAD_DIR}
CMAKE_ARGS --target install -DBENCHMARK_ENABLE_GTEST_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_USE_LIBCXX=${CPPDUALS_USE_LIBCXX}
"-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
INSTALL_DIR "${DEPS_ROOT}"
)
ExternalProject_Get_Property (benchmarkX source_dir)
ExternalProject_Get_Property (benchmarkX install_dir)
if (hasParent)
set (BENCHMARK_SRC_DIR "${source_dir}" PARENT_SCOPE)
set (BENCHMARK_INC_DIR "${install_dir}/include" PARENT_SCOPE)
message (" BENCHMARK_SRC_DIR: ${BENCHMARK_SRC_DIR}")
endif()
if (Boost_FOUND AND NO)
#
# Audi + Piranha - needs boost
#
#boost 1.70
find_package (Boost 1.69)
if (hasParent)
set (Boost_FOUND ${Boost_FOUND} PARENT_SCOPE)
set (Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} PARENT_SCOPE)
endif ()
# piranha
ExternalProject_Add (piranhaX PREFIX piranhaX
URL https://github.com/bluescarni/piranha/archive/v0.11.tar.gz
URL_HASH MD5=33482f719f6b8a6a5316f9bd148f5b10
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ""
)
ExternalProject_Get_Property (piranhaX source_dir)
if (hasParent)
set (PIRANHA_INCLUDE_DIR "${source_dir}/include" PARENT_SCOPE)
endif ()
# AuDi
ExternalProject_Add (audiX PREFIX audiX
URL https://github.com/darioizzo/audi/archive/v1.6.5.tar.gz
URL_HASH MD5=a51897469dfce4ceaa25e65519a346b9
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
#CONFIGURE_COMMAND ""
CMAKE_ARGS -DAUDI_BUILD_TESTS=OFF
BUILD_COMMAND "" INSTALL_COMMAND ""
)
ExternalProject_Get_Property (audiX source_dir)
if (hasParent)
set (AUDI_INCLUDE_DIR "${source_dir}/include" PARENT_SCOPE)
endif ()
endif (Boost_FOUND AND NO)
endif (CPPDUALS_BENCHMARK)
#
# multi-precision math
#
if (0)
ExternalProject_Add (mpfrX
PREFIX mpfrX
URL https://www.mpfr.org/mpfr-current/mpfr-4.0.2.tar.bz2
URL_HASH MD5=6d8a8bb46fe09ff44e21cdbf84f5cdac
DOWNLOAD_DIR ${DOWNLOAD_DIR}
CONFIGURE_COMMAND "../mpfrX/configure" --prefix=<INSTALL_DIR>
#BUILD_COMMAND "make install"
#INSTALL_COMMAND "make install"
)
# clumsy download link - retrieves "archive.tar"
ExternalProject_Add (mprealX
PREFIX mprealX
URL "http://www.holoborodko.com/pavel/wp-content/plugins/download-monitor/download.php?id=4"
URL_HASH MD5=68ad2258eb4a1c699c407f0e7bee5125
DOWNLOAD_DIR ${DOWNLOAD_DIR}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property (mprealX source_dir)
ExternalProject_Get_Property (mpfrX INSTALL_DIR)
if (hasParent)
set (MPFR_INCLUDES "${INSTALL_DIR}/include" "${source_dir}" PARENT_SCOPE)
set (MPFR_LIBRARIES "${INSTALL_DIR}/lib/libmpfr.a" -lgmp PARENT_SCOPE)
message (" MPFR_INCLUDES: ${MPFR_INCLUDES}")
add_definitions (-DHAVE_MPFR)
endif (hasParent)
endif (0)

4
src/include/ngspice/bool.h

@ -2,10 +2,13 @@
#define ngspice_BOOL_H #define ngspice_BOOL_H
//typedef unsigned char bool; //typedef unsigned char bool;
#ifndef __cplusplus
typedef int bool; typedef int bool;
#endif
typedef int BOOL; typedef int BOOL;
#define BOOLEAN int #define BOOLEAN int
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
@ -13,4 +16,5 @@ typedef int BOOL;
#define YES 1 #define YES 1
#endif #endif

7
src/include/ngspice/cktdefs.h

@ -428,6 +428,10 @@ extern int DCpss(CKTcircuit *, int);
/* SP */ /* SP */
#endif #endif
#ifdef __cplusplus
extern "C"
{
#endif
extern int NaskQuest(CKTcircuit *, JOB *, int, IFvalue *); extern int NaskQuest(CKTcircuit *, JOB *, int, IFvalue *);
extern int NsetParm(CKTcircuit *, JOB *, int, IFvalue *); extern int NsetParm(CKTcircuit *, JOB *, int, IFvalue *);
extern int NIacIter(CKTcircuit *); extern int NIacIter(CKTcircuit *);
@ -445,6 +449,9 @@ extern int NIreinit(CKTcircuit *);
extern int NIsenReinit(CKTcircuit *); extern int NIsenReinit(CKTcircuit *);
extern int NIdIter (CKTcircuit *); extern int NIdIter (CKTcircuit *);
extern void NInzIter(CKTcircuit *, int, int); extern void NInzIter(CKTcircuit *, int, int);
#ifdef __cplusplus
}
#endif
#ifdef PREDICTOR #ifdef PREDICTOR
extern int NIpred(CKTcircuit *ckt); extern int NIpred(CKTcircuit *ckt);

2
src/spicelib/devices/Makefile.am

@ -27,6 +27,7 @@ SUBDIRS = \
isrc \ isrc \
hfet1 \ hfet1 \
hfet2 \ hfet2 \
hicum2 \
hisim2 \ hisim2 \
hisimhv1 \ hisimhv1 \
hisimhv2 \ hisimhv2 \
@ -88,6 +89,7 @@ DIST_SUBDIRS = \
isrc \ isrc \
hfet1 \ hfet1 \
hfet2 \ hfet2 \
hicum2 \
hisim2 \ hisim2 \
hisimhv1 \ hisimhv1 \
hisimhv2 \ hisimhv2 \

8
src/spicelib/devices/dev.c

@ -97,6 +97,7 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */
#include "dio/dioitf.h" #include "dio/dioitf.h"
#include "hfet1/hfetitf.h" #include "hfet1/hfetitf.h"
#include "hfet2/hfet2itf.h" #include "hfet2/hfet2itf.h"
#include "hicum2/hicum2itf.h"
#include "hisim2/hsm2itf.h" #include "hisim2/hsm2itf.h"
#include "hisimhv1/hsmhvitf.h" #include "hisimhv1/hsmhvitf.h"
#include "hisimhv2/hsmhv2itf.h" #include "hisimhv2/hsmhv2itf.h"
@ -126,7 +127,6 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */
#include "vdmos/vdmositf.h" #include "vdmos/vdmositf.h"
#ifdef ADMS #ifdef ADMS
#include "adms/hicum0/hicum0itf.h" #include "adms/hicum0/hicum0itf.h"
#include "adms/hicum2/hicum2itf.h"
#include "adms/mextram/bjt504titf.h" #include "adms/mextram/bjt504titf.h"
#include "adms/ekv/ekvitf.h" #include "adms/ekv/ekvitf.h"
#include "adms/psp102/psp102itf.h" #include "adms/psp102/psp102itf.h"
@ -170,6 +170,7 @@ static SPICEdev *(*static_devices[])(void) = {
get_dio_info, get_dio_info,
get_hfeta_info, get_hfeta_info,
get_hfet2_info, get_hfet2_info,
get_hicum_info,
get_hsm2_info, get_hsm2_info,
get_hsmhv_info, get_hsmhv_info,
get_hsmhv2_info, get_hsmhv2_info,
@ -207,7 +208,6 @@ static SPICEdev *(*static_devices[])(void) = {
#ifdef ADMS #ifdef ADMS
(SPICEdev *(*)(void)) get_hicum0_info, (SPICEdev *(*)(void)) get_hicum0_info,
(SPICEdev *(*)(void)) get_hicum2_info,
(SPICEdev *(*)(void)) get_bjt504t_info, (SPICEdev *(*)(void)) get_bjt504t_info,
(SPICEdev *(*)(void)) get_ekv_info, (SPICEdev *(*)(void)) get_ekv_info,
(SPICEdev *(*)(void)) get_psp102_info, (SPICEdev *(*)(void)) get_psp102_info,
@ -298,12 +298,12 @@ SPICEdev ** devices(void)
#define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \ #define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \
"bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \ "bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \
"cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \ "cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum0", "hicum2", "bjt504t", "ekv", "psp102"}
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum0", "bjt504t", "ekv", "psp102"}
#else #else
#define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \ #define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \
"bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \ "bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \
"cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \ "cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc"}
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum2"}
#endif #endif
int load_dev(char *name) { int load_dev(char *name) {
char *msg; char *msg;

1
src/spicelib/devices/dio/dioload.c

@ -223,7 +223,6 @@ next1: if (model->DIOsatSWCurGiven) { /* sidewall current */
} }
} else { /* merge saturation currents and use same characteristic as bottom diode */ } else { /* merge saturation currents and use same characteristic as bottom diode */
csat = csat + csatsw; csat = csat + csatsw;
} }

33
src/spicelib/devices/hicum2/Makefile.am

@ -0,0 +1,33 @@
## Process this file with automake to produce Makefile.in
noinst_LTLIBRARIES = libhicum2.la
libhicum2_la_SOURCES = \
hicum2.c \
hicum2acld.c \
hicum2ask.c \
hicum2conv.c \
hicum2defs.h \
hicum2ext.h \
hicum2getic.c \
hicum2init.c \
hicum2init.h \
hicum2itf.h \
hicumL2.hpp \
hicumL2.cpp \
hicumL2temp.hpp \
hicumL2temp.cpp \
hicum2mask.c \
hicum2mpar.c \
hicum2noise.c \
hicum2param.c \
hicum2pzld.c \
hicum2setup.c \
hicum2soachk.c \
hicum2trunc.c
AM_CFLAGS = -O -g -Wall -Wextra -I$(top_srcdir)/src/include
AM_CPPFLAGS = @AM_CPPFLAGS@ -O -g -Wall -Wextra
AM_CXXFLAGS = -I$(top_srcdir)/src/include/cppduals -I$(top_srcdir)/src/include -std=c++11 -O -g -Wall -Wextra
MAINTAINERCLEANFILES = Makefile.in

304
src/spicelib/devices/hicum2/hicum2.c

@ -0,0 +1,304 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This file defines the HICUM data structures that are
* available to the next level(s) up the calling hierarchy
*/
#include "ngspice/ngspice.h"
#include "ngspice/devdefs.h"
#include "hicum2defs.h"
#include "ngspice/suffix.h"
IFparm HICUMpTable[] = { /* parameters */
IOPU("area", HICUM_AREA, IF_REAL, "Area factor"),
IOPU("off", HICUM_OFF, IF_FLAG, "Device initially off"),
IP("ic", HICUM_IC, IF_REALVEC, "Initial condition vector"),
// these are left here for future. Sometimes it is advantageous for debugging if one can set the initial node voltages of all nodes.
// OP("icvb", HICUM_IC_VB, IF_REAL, "Initial B potential"),
// OP("icvc", HICUM_IC_VC, IF_REAL, "Initial C potential"),
// OP("icve", HICUM_IC_VE, IF_REAL, "Initial E potential"),
// OP("icvbi", HICUM_IC_VBi, IF_REAL, "Initial Bi potential"),
// OP("icvbp", HICUM_IC_VBp, IF_REAL, "Initial Bp potential"),
// OP("icvci", HICUM_IC_VCi, IF_REAL, "Initial Ci potential"),
// OP("icvt", HICUM_IC_Vt, IF_REAL, "Initial T potential"),
// OP("icvei", HICUM_IC_VEi, IF_REAL, "Initial Ei potential"),
IOPU("m", HICUM_M, IF_REAL, "Multiplier"),
IOPU("temp", HICUM_TEMP, IF_REAL, "Instance temperature"),
IP("dt", HICUM_DTEMP, IF_REAL, "Instance delta temperature"),
IOPU("tk", HICUM_QUEST_TK, IF_REAL, "Actual device temperature"),
IOPU("dtsh", HICUM_QUEST_DTSH, IF_REAL, "Temperature increase due to self-heating"),
IOPU("it", HICUM_QUEST_IT, IF_REAL, "transfer current"),
OPU("collnode", HICUM_QUEST_COLLNODE, IF_INTEGER, "Number of collector node"),
OPU("basenode", HICUM_QUEST_BASENODE, IF_INTEGER, "Number of base node"),
OPU("emitnode", HICUM_QUEST_EMITNODE, IF_INTEGER, "Number of emitter node"),
OPU("subsnode", HICUM_QUEST_SUBSNODE, IF_INTEGER, "Number of substrate node"),
OPU("tempnode", HICUM_QUEST_TEMPNODE, IF_INTEGER, "Number of temperature node"),
OPU("collCInode", HICUM_QUEST_COLLCINODE, IF_INTEGER, "Internal collector node"),
OPU("baseBPnode", HICUM_QUEST_BASEBPNODE, IF_INTEGER, "External base node"),
OPU("baseBInode", HICUM_QUEST_BASEBINODE, IF_INTEGER, "Internal base node"),
OPU("emitEInode", HICUM_QUEST_EMITEINODE, IF_INTEGER, "Internal emitter node"),
OPU("subsSInode", HICUM_QUEST_SUBSSINODE, IF_INTEGER, "Internal substrate node"),
OPU("xfnode", HICUM_QUEST_XFNODE, IF_INTEGER, "Internal phase node xf"),
OPU("xf1node", HICUM_QUEST_XF1NODE, IF_INTEGER, "Internal phase node xf1"),
OPU("xf2node", HICUM_QUEST_XF2NODE, IF_INTEGER, "Internal phase node xf2"),
/* voltages */
OP("vbe", HICUM_QUEST_VBE, IF_REAL, "External BE voltage"),
OP("vbbp", HICUM_QUEST_VBBP, IF_REAL, "BBP voltage"),
OP("vbc", HICUM_QUEST_VBC, IF_REAL, "External BC voltage"),
OP("vce", HICUM_QUEST_VCE, IF_REAL, "External CE voltage"),
OP("vsc", HICUM_QUEST_VSC, IF_REAL, "External SC voltage"),
OP("vbiei", HICUM_QUEST_VBIEI, IF_REAL, "Internal BE voltage"),
OP("vbpbi", HICUM_QUEST_VBPBI, IF_REAL, "Peripheral Base to internal Base voltage"),
OP("vbici", HICUM_QUEST_VBICI, IF_REAL, "Internal BC voltage"),
OP("vciei", HICUM_QUEST_VCIEI, IF_REAL, "Interal CE voltage"),
/* currents */
OP("ic", HICUM_QUEST_CC, IF_REAL, "Collector current"),
OP("iavl", HICUM_QUEST_CAVL, IF_REAL, "Avalanche current"),
OP("ib", HICUM_QUEST_CB, IF_REAL, "Base current"),
OP("ibei", HICUM_QUEST_CBEI, IF_REAL, "Intenral Base Emitter current"),
OP("ibci", HICUM_QUEST_CBCI, IF_REAL, "Internal Base Collector current"),
OP("ie", HICUM_QUEST_CE, IF_REAL, "Emitter current"),
OP("is", HICUM_QUEST_CS, IF_REAL, "Substrate current"),
/* resistances */
OP("rcx_t", HICUM_QUEST_RCX_T, IF_REAL, "External (saturated) collector series resistance"),
OP("re_t", HICUM_QUEST_RE_T, IF_REAL, "Emitter series resistance"),
OP("rbi", HICUM_QUEST_RBI, IF_REAL, "Internal base resistance as calculated in the model"),
OP("rb", HICUM_QUEST_RB, IF_REAL, "Total base resistance as calculated in the model"),
/* transconductances and capacitances */
OP("betadc", HICUM_QUEST_BETADC, IF_REAL, "Common emitter forward current gain"),
OP("gmi", HICUM_QUEST_GMI, IF_REAL, "Internal transconductance"),
OP("gms", HICUM_QUEST_GMS, IF_REAL, "Transconductance of the parasitic substrate PNP"),
OP("rpii", HICUM_QUEST_RPII, IF_REAL, "Internal base-emitter (input) resistance"),
OP("rpix", HICUM_QUEST_RPIX, IF_REAL, "External base-emitter (input) resistance"),
OP("rmui", HICUM_QUEST_RMUI, IF_REAL, "Internal feedback resistance"),
OP("rmux", HICUM_QUEST_RMUX, IF_REAL, "External feedback resistance"),
OP("roi", HICUM_QUEST_ROI, IF_REAL, "Output resistance"),
OP("cpii", HICUM_QUEST_CPII, IF_REAL, "Total internal BE capacitance"),
OP("cpix", HICUM_QUEST_CPIX, IF_REAL, "Total external BE capacitance"),
OP("cmui", HICUM_QUEST_CMUI, IF_REAL, "Total internal BC capacitance"),
OP("cmux", HICUM_QUEST_CMUX, IF_REAL, "Total external BC capacitance"),
OP("ccs", HICUM_QUEST_CCS, IF_REAL, "CS junction capacitance"),
OP("betaac", HICUM_QUEST_BETAAC, IF_REAL, "Small signal current gain"),
OP("crbi", HICUM_QUEST_CRBI, IF_REAL, "Shunt capacitance across RBI as calculated in the model"),
/* transit time */
OP("tf", HICUM_QUEST_TF, IF_REAL, "Forward transit time"),
OP("ft", HICUM_QUEST_FT, IF_REAL, "Transit frequency"),
OP("ick", HICUM_QUEST_ICK, IF_REAL, "Transit frequency"),
/* power */
OP("p", HICUM_QUEST_POWER, IF_REAL, "Power dissipation")
};
IFparm HICUMmPTable[] = { /* model parameters */
//Circuit simulator specific parameters
IOP("type", HICUM_MOD_TYPE, IF_STRING, "For transistor type NPN(+1) or PNP (-1)"),
IOPU("npn", HICUM_MOD_NPN, IF_FLAG, "NPN type device"),
IOPU("pnp", HICUM_MOD_PNP, IF_FLAG, "PNP type device"),
IOP("tnom", HICUM_MOD_TNOM, IF_REAL, "Temperature at which parameters are specified"),
IOPR("tref", HICUM_MOD_TNOM, IF_REAL, "Temperature at which parameters are specified"),
IOP("version", HICUM_MOD_VERSION, IF_STRING, " parameter for model version"),
//Transfer current
IOP("c10", HICUM_MOD_C10 , IF_REAL, "GICCR constant"),
IOP("qp0", HICUM_MOD_QP0 , IF_REAL, "Zero-bias hole charge"),
IOP("ich", HICUM_MOD_ICH , IF_REAL, "High-current correction for 2D and 3D effects"), //`0' signifies infinity
IOP("hf0", HICUM_MOD_HF0 , IF_REAL, "Weight factor for the low current minority charge"),
IOP("hfe", HICUM_MOD_HFE , IF_REAL, "Emitter minority charge weighting factor in HBTs"),
IOP("hfc", HICUM_MOD_HFC , IF_REAL, "Collector minority charge weighting factor in HBTs"),
IOP("hjei", HICUM_MOD_HJEI , IF_REAL, "B-E depletion charge weighting factor in HBTs"),
IOP("ahjei", HICUM_MOD_AHJEI, IF_REAL, "Parameter describing the slope of hjEi(VBE)"),
IOP("rhjei", HICUM_MOD_RHJEI, IF_REAL, "Smoothing parameter for hjEi(VBE) at high voltage"),
IOP("hjci", HICUM_MOD_HJCI , IF_REAL, "B-C depletion charge weighting factor in HBTs"),
//Base-Emitter diode currents
IOP("ibeis", HICUM_MOD_IBEIS, IF_REAL, "Internal B-E saturation current"),
IOP("mbei", HICUM_MOD_MBEI , IF_REAL, "Internal B-E current ideality factor"),
IOP("ireis", HICUM_MOD_IREIS, IF_REAL, "Internal B-E recombination saturation current"),
IOP("mrei", HICUM_MOD_MREI , IF_REAL, "Internal B-E recombination current ideality factor"),
IOP("ibeps", HICUM_MOD_IBEPS, IF_REAL, "Peripheral B-E saturation current"),
IOP("mbep", HICUM_MOD_MBEP , IF_REAL, "Peripheral B-E current ideality factor"),
IOP("ireps", HICUM_MOD_IREPS, IF_REAL, "Peripheral B-E recombination saturation current"),
IOP("mrep", HICUM_MOD_MREP , IF_REAL, "Peripheral B-E recombination current ideality factor"),
IOP("mcf", HICUM_MOD_MCF , IF_REAL, "Non-ideality factor for III-V HBTs"),
//Transit time for excess recombination current at b-c barrier
IOP("tbhrec", HICUM_MOD_TBHREC, IF_REAL, "Base current recombination time constant at B-C barrier for high forward injection"),
//Base-Collector diode currents
IOP("ibcis", HICUM_MOD_IBCIS, IF_REAL, "Internal B-C saturation current"),
IOP("mbci", HICUM_MOD_MBCI , IF_REAL, "Internal B-C current ideality factor"),
IOP("ibcxs", HICUM_MOD_IBCXS, IF_REAL, "External B-C saturation current"),
IOP("mbcx", HICUM_MOD_MBCX , IF_REAL, "External B-C current ideality factor"),
//Base-Emitter tunneling current
IOP("ibets", HICUM_MOD_IBETS, IF_REAL, "B-E tunneling saturation current"),
IOP("abet", HICUM_MOD_ABET, IF_REAL, "Exponent factor for tunneling current"),
IOP("tunode",HICUM_MOD_TUNODE, IF_INTEGER, "Specifies the base node connection for the tunneling current"), // =1 signifies perimeter node
//Base-Collector avalanche current
IOP("favl", HICUM_MOD_FAVL , IF_REAL, "Avalanche current factor"),
IOP("qavl", HICUM_MOD_QAVL , IF_REAL, "Exponent factor for avalanche current"),
IOP("kavl", HICUM_MOD_KAVL , IF_REAL, "Flag/factor for turning strong avalanche on"),
IOP("alfav", HICUM_MOD_ALFAV, IF_REAL, "Relative TC for FAVL"),
IOP("alqav", HICUM_MOD_ALQAV, IF_REAL, "Relative TC for QAVL"),
IOP("alkav", HICUM_MOD_ALKAV, IF_REAL, "Relative TC for KAVL"),
//Series resistances
IOP("rbi0", HICUM_MOD_RBI0 , IF_REAL, "Zero bias internal base resistance"),
IOP("rbx", HICUM_MOD_RBX , IF_REAL, "External base series resistance"),
IOP("fgeo", HICUM_MOD_FGEO , IF_REAL, "Factor for geometry dependence of emitter current crowding"),
IOP("fdqr0", HICUM_MOD_FDQR0, IF_REAL, "Correction factor for modulation by B-E and B-C space charge layer"),
IOP("fcrbi", HICUM_MOD_FCRBI, IF_REAL, "Ratio of HF shunt to total internal capacitance (lateral NQS effect)"),
IOP("fqi", HICUM_MOD_FQI , IF_REAL, "Ration of internal to total minority charge"),
IOP("re", HICUM_MOD_RE , IF_REAL, "Emitter series resistance"),
IOP("rcx", HICUM_MOD_RCX , IF_REAL, "External collector series resistance"),
//Substrate transistor
IOP("itss", HICUM_MOD_ITSS, IF_REAL, "Substrate transistor transfer saturation current"),
IOP("msf", HICUM_MOD_MSF , IF_REAL, "Forward ideality factor of substrate transfer current"),
IOP("iscs", HICUM_MOD_ISCS, IF_REAL, "C-S diode saturation current"),
IOP("msc", HICUM_MOD_MSC , IF_REAL, "Ideality factor of C-S diode current"),
IOP("tsf", HICUM_MOD_TSF , IF_REAL, "Transit time for forward operation of substrate transistor"),
//Intra-device substrate coupling
IOP("rsu", HICUM_MOD_RSU, IF_REAL, "Substrate series resistance"),
IOP("csu", HICUM_MOD_CSU, IF_REAL, "Substrate shunt capacitance"),
//Depletion Capacitances
IOP("cjei0", HICUM_MOD_CJEI0 , IF_REAL, "Internal B-E zero-bias depletion capacitance"),
IOP("vdei", HICUM_MOD_VDEI , IF_REAL, "Internal B-E built-in potential"),
IOP("zei", HICUM_MOD_ZEI , IF_REAL, "Internal B-E grading coefficient"),
IOP("ajei", HICUM_MOD_AJEI , IF_REAL, "Ratio of maximum to zero-bias value of internal B-E capacitance"),
IOPR("aljei", HICUM_MOD_AJEI , IF_REAL, "Ratio of maximum to zero-bias value of internal B-E capacitance"),
IOP("cjep0", HICUM_MOD_CJEP0 , IF_REAL, "Peripheral B-E zero-bias depletion capacitance"),
IOP("vdep", HICUM_MOD_VDEP , IF_REAL, "Peripheral B-E built-in potential"),
IOP("zep", HICUM_MOD_ZEP , IF_REAL, "Peripheral B-E grading coefficient"),
IOP("ajep", HICUM_MOD_AJEP , IF_REAL, "Ratio of maximum to zero-bias value of peripheral B-E capacitance"),
IOPR("aljep", HICUM_MOD_AJEP , IF_REAL, "Ratio of maximum to zero-bias value of peripheral B-E capacitance"),
IOP("cjci0", HICUM_MOD_CJCI0 , IF_REAL, "Internal B-C zero-bias depletion capacitance"),
IOP("vdci", HICUM_MOD_VDCI , IF_REAL, "Internal B-C built-in potential"),
IOP("zci", HICUM_MOD_ZCI , IF_REAL, "Internal B-C grading coefficient"),
IOP("vptci", HICUM_MOD_VPTCI , IF_REAL, "Internal B-C punch-through voltage"),
IOP("cjcx0", HICUM_MOD_CJCX0 , IF_REAL, "External B-C zero-bias depletion capacitance"),
IOP("vdcx", HICUM_MOD_VDCX , IF_REAL, "External B-C built-in potential"),
IOP("zcx", HICUM_MOD_ZCX , IF_REAL, "External B-C grading coefficient"),
IOP("vptcx", HICUM_MOD_VPTCX , IF_REAL, "External B-C punch-through voltage"),
IOP("fbcpar", HICUM_MOD_FBCPAR, IF_REAL, "Partitioning factor of parasitic B-C cap"),
IOPR("fbc", HICUM_MOD_FBCPAR, IF_REAL, "Partitioning factor of parasitic B-C cap"),
IOP("fbepar", HICUM_MOD_FBEPAR, IF_REAL, "Partitioning factor of parasitic B-E cap"),
IOPR("fbe", HICUM_MOD_FBEPAR, IF_REAL, "Partitioning factor of parasitic B-E cap"),
IOP("cjs0", HICUM_MOD_CJS0 , IF_REAL, "C-S zero-bias depletion capacitance"),
IOP("vds", HICUM_MOD_VDS , IF_REAL, "C-S built-in potential"),
IOP("zs", HICUM_MOD_ZS , IF_REAL, "C-S grading coefficient"),
IOP("vpts", HICUM_MOD_VPTS , IF_REAL, "C-S punch-through voltage"),
IOP("cscp0", HICUM_MOD_CSCP0 , IF_REAL, "Perimeter S-C zero-bias depletion capacitance"),
IOP("vdsp", HICUM_MOD_VDSP , IF_REAL, "Perimeter S-C built-in potential"),
IOP("zsp", HICUM_MOD_ZSP , IF_REAL, "Perimeter S-C grading coefficient"),
IOP("vptsp", HICUM_MOD_VPTSP , IF_REAL, "Perimeter S-C punch-through voltage"),
//Diffusion Capacitances
IOP("t0", HICUM_MOD_T0 , IF_REAL, "Low current forward transit time at VBC=0V"),
IOP("dt0h", HICUM_MOD_DT0H , IF_REAL, "Time constant for base and B-C space charge layer width modulation"),
IOP("tbvl", HICUM_MOD_TBVL , IF_REAL, "Time constant for modeling carrier jam at low VCE"),
IOP("tef0", HICUM_MOD_TEF0 , IF_REAL, "Neutral emitter storage time"),
IOP("gtfe", HICUM_MOD_GTFE , IF_REAL, "Exponent factor for current dependence of neutral emitter storage time"),
IOP("thcs", HICUM_MOD_THCS , IF_REAL, "Saturation time constant at high current densities"),
IOP("ahc", HICUM_MOD_AHC , IF_REAL, "Smoothing factor for current dependence of base and collector transit time"),
IOPR("alhc", HICUM_MOD_AHC , IF_REAL, "Smoothing factor for current dependence of base and collector transit time"),
IOP("fthc", HICUM_MOD_FTHC , IF_REAL, "Partitioning factor for base and collector portion"),
IOP("rci0", HICUM_MOD_RCI0 , IF_REAL, "Internal collector resistance at low electric field"),
IOP("vlim", HICUM_MOD_VLIM , IF_REAL, "Voltage separating ohmic and saturation velocity regime"),
IOP("vces", HICUM_MOD_VCES , IF_REAL, "Internal C-E saturation voltage"),
IOP("vpt", HICUM_MOD_VPT , IF_REAL, "Collector punch-through voltage"), // `0' signifies infinity
IOP("aick", HICUM_MOD_AICK , IF_REAL, "Smoothing term for ICK"),
IOP("delck", HICUM_MOD_DELCK, IF_REAL, "Fitting factor for critical current"),
IOP("tr", HICUM_MOD_TR , IF_REAL, "Storage time for inverse operation"),
IOP("vcbar", HICUM_MOD_VCBAR, IF_REAL, "Barrier voltage"),
IOP("icbar", HICUM_MOD_ICBAR, IF_REAL, "Normalization parameter"),
IOP("acbar", HICUM_MOD_ACBAR, IF_REAL, "Smoothing parameter for barrier voltage"),
//Isolation Capacitances
IOP("cbepar", HICUM_MOD_CBEPAR, IF_REAL, "Total parasitic B-E capacitance"),
IOPR("ceox", HICUM_MOD_CBEPAR, IF_REAL, "Total parasitic B-E capacitance"),
IOP("cbcpar", HICUM_MOD_CBCPAR, IF_REAL, "Total parasitic B-C capacitance"),
IOPR("ccox", HICUM_MOD_CBCPAR, IF_REAL, "Total parasitic B-C capacitance"),
//Non-quasi-static Effect
IOP("alqf", HICUM_MOD_ALQF, IF_REAL, "Factor for additional delay time of minority charge"),
IOP("alit", HICUM_MOD_ALIT, IF_REAL, "Factor for additional delay time of transfer current"),
IOP("flnqs", HICUM_MOD_FLNQS, IF_INTEGER, "Flag for turning on and off of vertical NQS effect"),
//Noise
IOP("kf", HICUM_MOD_KF , IF_REAL, "Flicker noise coefficient"),
IOP("af", HICUM_MOD_AF , IF_REAL, "Flicker noise exponent factor"),
IOP("cfbe", HICUM_MOD_CFBE , IF_INTEGER, "Flag for determining where to tag the flicker noise source"),
IOP("flcono", HICUM_MOD_FLCONO, IF_INTEGER, "Flag for turning on and off of correlated noise implementation"),
IOP("kfre", HICUM_MOD_KFRE , IF_REAL, "Emitter resistance flicker noise coefficient"),
IOP("afre", HICUM_MOD_AFRE , IF_REAL, "Emitter resistance flicker noise exponent factor"),
//Lateral Geometry Scaling (at high current densities)
IOP("latb", HICUM_MOD_LATB, IF_REAL, "Scaling factor for collector minority charge in direction of emitter width"),
IOP("latl", HICUM_MOD_LATL, IF_REAL, "Scaling factor for collector minority charge in direction of emitter length"),
//Temperature dependence
IOP("vgb", HICUM_MOD_VGB , IF_REAL, "Bandgap voltage extrapolated to 0 K"),
IOP("alt0", HICUM_MOD_ALT0 , IF_REAL, "First order relative TC of parameter T0"),
IOP("kt0", HICUM_MOD_KT0 , IF_REAL, "Second order relative TC of parameter T0"),
IOP("zetaci", HICUM_MOD_ZETACI , IF_REAL, "Temperature exponent for RCI0"),
IOP("alvs", HICUM_MOD_ALVS , IF_REAL, "Relative TC of saturation drift velocity"),
IOP("alces", HICUM_MOD_ALCES , IF_REAL, "Relative TC of VCES"),
IOP("zetarbi", HICUM_MOD_ZETARBI , IF_REAL, "Temperature exponent of internal base resistance"),
IOP("zetarbx", HICUM_MOD_ZETARBX , IF_REAL, "Temperature exponent of external base resistance"),
IOP("zetarcx", HICUM_MOD_ZETARCX , IF_REAL, "Temperature exponent of external collector resistance"),
IOP("zetare", HICUM_MOD_ZETARE , IF_REAL, "Temperature exponent of emitter resistance"),
IOP("zetacx", HICUM_MOD_ZETACX , IF_REAL, "Temperature exponent of mobility in substrate transistor transit time"),
IOP("vge", HICUM_MOD_VGE , IF_REAL, "Effective emitter bandgap voltage"),
IOP("vgc", HICUM_MOD_VGC , IF_REAL, "Effective collector bandgap voltage"),
IOP("vgs", HICUM_MOD_VGS , IF_REAL, "Effective substrate bandgap voltage"),
IOP("f1vg", HICUM_MOD_F1VG , IF_REAL, "Coefficient K1 in T-dependent band-gap equation"),
IOP("f2vg", HICUM_MOD_F2VG , IF_REAL, "Coefficient K2 in T-dependent band-gap equation"),
IOP("zetact", HICUM_MOD_ZETACT , IF_REAL, "Exponent coefficient in transfer current temperature dependence"),
IOP("zetabet", HICUM_MOD_ZETABET , IF_REAL, "Exponent coefficient in B-E junction current temperature dependence"),
IOP("alb", HICUM_MOD_ALB , IF_REAL, "Relative TC of forward current gain for V2.1 model"),
IOP("dvgbe", HICUM_MOD_DVGBE , IF_REAL, "Bandgap difference between B and B-E junction used for hjEi0 and hf0"),
IOP("zetahjei", HICUM_MOD_ZETAHJEI, IF_REAL, "Temperature coefficient for ahjEi"),
IOP("zetavgbe", HICUM_MOD_ZETAVGBE, IF_REAL, "Temperature coefficient for hjEi0"),
//Self-Heating
IOP("flsh", HICUM_MOD_FLSH , IF_INTEGER, "Flag for turning on and off self-heating effect"),
IOP("rth", HICUM_MOD_RTH , IF_REAL, "Thermal resistance"),
IOP("zetarth", HICUM_MOD_ZETARTH, IF_REAL, "Temperature coefficient for Rth"),
IOP("alrth", HICUM_MOD_ALRTH , IF_REAL, "First order relative TC of parameter Rth"),
IOP("cth", HICUM_MOD_CTH , IF_REAL, "Thermal capacitance"),
//Compatibility with V2.1
IOP("flcomp", HICUM_MOD_FLCOMP, IF_REAL, "Flag for compatibility with v2.1 model (0=v2.1)"),
IOP("vbe_max", HICUM_MOD_VBE_MAX, IF_REAL, "maximum voltage B-E junction"),
IOP("vbc_max", HICUM_MOD_VBC_MAX, IF_REAL, "maximum voltage B-C junction"),
IOP("vce_max", HICUM_MOD_VCE_MAX, IF_REAL, "maximum voltage C-E branch")
};
char *HICUMnames[] = {
"collector",
"base",
"emitter",
"substrate",
"temp"
};
int HICUMnSize = NUMELEMS(HICUMnames);
int HICUMpTSize = NUMELEMS(HICUMpTable);
int HICUMmPTSize = NUMELEMS(HICUMmPTable);
int HICUMiSize = sizeof(HICUMinstance);
int HICUMmSize = sizeof(HICUMmodel);

645
src/spicelib/devices/hicum2/hicum2acld.c

@ -0,0 +1,645 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* Function to load the COMPLEX circuit matrix using the
* small signal parameters saved during a previous DC operating
* point analysis.
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
HICUMacLoad(GENmodel *inModel, CKTcircuit *ckt)
{
HICUMinstance *here;
HICUMmodel *model = (HICUMmodel*)inModel;
double Ibpei_Vbpei;
double Ibpei_Vrth;
double Ibiei_Vbiei;
double Ibiei_Vxf;
double Ibiei_Vbici;
double Ibiei_Vrth;
double Ibici_Vbici;
double Ibici_Vbiei;
double Ibici_Vrth;
double Ibpci_Vbpci;
double Ibpci_Vrth;
double Isici_Vsici;
double Isici_Vrth;
double Iciei_Vbiei;
double Iciei_Vbici;
double Iciei_Vrth;
double Iciei_Vxf2;
double Ibpbi_Vbpbi;
double Ibpbi_Vbici;
double Ibpbi_Vbiei;
double Ibpbi_Vrth;
double Isis_Vsis;
double Irth_Vrth;
double Icic_Vcic, Icic_Vrth;
double Ieie_Veie, Ieie_Vrth;
double Ibbp_Vbbp, Ibbp_Vrth;
double Ibpsi_Vbpci;
double Ibpsi_Vsici;
double Ibpsi_Vrth;
double XQrbi_Vbpbi;
double XQrbi_Vbiei;
double XQrbi_Vbici;
double XQrbi_Vrth;
double XQjei_Vbiei;
double XQjei_Vrth;
double XQjci_Vbici;
double XQjci_Vrth;
double XQjep_Vbpei;
double XQjep_Vrth;
double volatile Xqjcx0_t_i_Vbci;
double Xqjcx0_t_i_Vrth;
double volatile Xqjcx0_t_ii_Vbpci;
double Xqjcx0_t_ii_Vrth;
double XQdsu_Vbpci;
double XQdsu_Vsici;
double XQdsu_Vrth;
double XQjs_Vsici;
double XQjs_Vrth;
double XQscp_Vsc;
double XQscp_Vrth;
double XQbepar1_Vbe;
double XQbepar2_Vbpe;
double XQbcpar1_Vbci;
double XQbcpar2_Vbpci;
double XQsu_Vsis;
double XQcth_Vrth;
double XQf_Vbiei;
double XQf_Vbici;
double XQf_Vrth;
double XQf_Vxf;
double XQr_Vrth;
double XQr_Vbiei;
double XQr_Vbici;
double XQxf_Vxf;
double XQxf1_Vxf1;
double XQxf2_Vxf2;
double Ixf1_Vbiei;
double Ixf1_Vbici;
double Ixf1_Vxf2 ;
double Ixf1_Vxf1 ;
double Ixf1_Vrth ;
double Ixf2_Vbiei;
double Ixf2_Vbici;
double Ixf2_Vxf2 ;
double Ixf2_Vxf1 ;
double Ixf2_Vrth ;
double Ixf_Vbiei ;
double Ixf_Vbici ;
double Ixf_Vxf ;
double Ixf_Vrth ;
double Ith_Vrth, Ith_Vbiei, Ith_Vbici, Ith_Vbpbi, Ith_Vbpci, Ith_Vbpei, Ith_Vciei, Ith_Vsici, Ith_Vcic, Ith_Vbbp, Ith_Veie;
/* loop through all the models */
for( ; model != NULL; model = HICUMnextModel(model)) {
int selfheat = ( (model->HICUMflsh > 0) && (model->HICUMrthGiven) && (model->HICUMrth > 0.0));
int nqs = ( (model->HICUMflnqs != 0 || model->HICUMflcomp < 2.3) && (model->HICUMalit > 0 || model->HICUMalqf > 0));
/* loop through all the instances of the model */
for( here = HICUMinstances(model); here!= NULL;
here = HICUMnextInstance(here)) {
// get all derivatives of branch DC currents
if(model->HICUMrcxGiven && model->HICUMrcx != 0) {
Icic_Vcic = 1/here->HICUMrcx_t.rpart;
Icic_Vrth = -*(ckt->CKTstate0 + here->HICUMvcic)/here->HICUMrcx_t.rpart/here->HICUMrcx_t.rpart*here->HICUMrcx_t.dpart;
} else {
Icic_Vcic = 0.0;
Icic_Vrth = 0.0;
}
if(model->HICUMrbxGiven && model->HICUMrbx != 0) {
Ibbp_Vbbp = 1/here->HICUMrbx_t.rpart;
Ibbp_Vrth = -*(ckt->CKTstate0 + here->HICUMvbbp)/here->HICUMrbx_t.rpart/here->HICUMrbx_t.rpart*here->HICUMrbx_t.dpart;
} else {
Ibbp_Vbbp = 0.0;
Ibbp_Vrth = 0.0;
}
if(model->HICUMreGiven && model->HICUMre != 0) {
Ieie_Veie = 1/here->HICUMre_t.rpart;
Ieie_Vrth = -*(ckt->CKTstate0 + here->HICUMveie)/here->HICUMre_t.rpart/here->HICUMre_t.rpart*here->HICUMre_t.dpart;
} else {
Ieie_Veie = 0.0;
Ieie_Vrth = 0.0;
}
if(model->HICUMrsuGiven && model->HICUMrsu != 0) {
Isis_Vsis = 1/model->HICUMrsu*here->HICUMm;
} else {
Isis_Vsis = 0.0;
}
if(selfheat) {
Irth_Vrth = (1/here->HICUMrth_t.rpart - *(ckt->CKTstate0 + here->HICUMvrth)/(here->HICUMrth_t.rpart*here->HICUMrth_t.rpart) * here->HICUMrth_t.dpart);
} else {
Irth_Vrth = 0.0;
}
Ibiei_Vbiei = *(ckt->CKTstate0 + here->HICUMibiei_Vbiei);
Ibiei_Vxf = *(ckt->CKTstate0 + here->HICUMibiei_Vxf);
Ibiei_Vbici = *(ckt->CKTstate0 + here->HICUMibiei_Vbici);
Ibiei_Vrth = *(ckt->CKTstate0 + here->HICUMibiei_Vrth);
Ibpei_Vbpei = *(ckt->CKTstate0 + here->HICUMibpei_Vbpei);
Ibpei_Vrth = *(ckt->CKTstate0 + here->HICUMibpei_Vrth);
Iciei_Vbiei = *(ckt->CKTstate0 + here->HICUMiciei_Vbiei);
Iciei_Vbici = *(ckt->CKTstate0 + here->HICUMiciei_Vbici);
Iciei_Vrth = *(ckt->CKTstate0 + here->HICUMiciei_Vrth);
Iciei_Vxf2 = *(ckt->CKTstate0 + here->HICUMiciei_Vxf2);
Ibici_Vbici = *(ckt->CKTstate0 + here->HICUMibici_Vbici);
Ibici_Vbiei = *(ckt->CKTstate0 + here->HICUMibici_Vbiei);
Ibici_Vrth = *(ckt->CKTstate0 + here->HICUMibici_Vrth);
Ibpbi_Vbpbi = *(ckt->CKTstate0 + here->HICUMibpbi_Vbpbi);
Ibpbi_Vbiei = *(ckt->CKTstate0 + here->HICUMibpbi_Vbiei);
Ibpbi_Vbici = *(ckt->CKTstate0 + here->HICUMibpbi_Vbici);
Ibpbi_Vrth = *(ckt->CKTstate0 + here->HICUMibpbi_Vrth);
Ibpci_Vbpci = *(ckt->CKTstate0 + here->HICUMibpci_Vbpci);
Ibpci_Vrth = *(ckt->CKTstate0 + here->HICUMibpci_Vrth);
Isici_Vsici = *(ckt->CKTstate0 + here->HICUMisici_Vsici);
Isici_Vrth = *(ckt->CKTstate0 + here->HICUMisici_Vrth);
Ibpsi_Vbpci = *(ckt->CKTstate0 + here->HICUMibpsi_Vbpci);
Ibpsi_Vsici = *(ckt->CKTstate0 + here->HICUMibpsi_Vsici);
Ibpsi_Vrth = *(ckt->CKTstate0 + here->HICUMibpsi_Vrth);
Ith_Vrth = *(ckt->CKTstate0 + here->HICUMith_Vrth);
Ith_Vbiei = *(ckt->CKTstate0 + here->HICUMith_Vbiei);
Ith_Vbici = *(ckt->CKTstate0 + here->HICUMith_Vbici);
Ith_Vbpbi = *(ckt->CKTstate0 + here->HICUMith_Vbpbi);
Ith_Vbpci = *(ckt->CKTstate0 + here->HICUMith_Vbpci);
Ith_Vbpei = *(ckt->CKTstate0 + here->HICUMith_Vbpei);
Ith_Vciei = *(ckt->CKTstate0 + here->HICUMith_Vciei);
Ith_Vsici = *(ckt->CKTstate0 + here->HICUMith_Vsici);
Ith_Vcic = *(ckt->CKTstate0 + here->HICUMith_Vcic);
Ith_Vbbp = *(ckt->CKTstate0 + here->HICUMith_Vbbp);
Ith_Veie = *(ckt->CKTstate0 + here->HICUMith_Veie);
Ixf1_Vbiei = *(ckt->CKTstate0 + here->HICUMixf1_Vbiei);
Ixf1_Vbici = *(ckt->CKTstate0 + here->HICUMixf1_Vbici);
Ixf1_Vxf2 = *(ckt->CKTstate0 + here->HICUMixf1_Vxf2);
Ixf1_Vxf1 = *(ckt->CKTstate0 + here->HICUMixf1_Vxf1);
Ixf1_Vrth = *(ckt->CKTstate0 + here->HICUMixf1_Vrth);
Ixf2_Vbiei = *(ckt->CKTstate0 + here->HICUMixf2_Vbiei);
Ixf2_Vbici = *(ckt->CKTstate0 + here->HICUMixf2_Vbici);
Ixf2_Vxf2 = *(ckt->CKTstate0 + here->HICUMixf2_Vxf2);
Ixf2_Vxf1 = *(ckt->CKTstate0 + here->HICUMixf2_Vxf1);
Ixf2_Vrth = *(ckt->CKTstate0 + here->HICUMixf2_Vrth);
Ixf_Vbiei = *(ckt->CKTstate0 + here->HICUMixf_Vbiei);
Ixf_Vbici = *(ckt->CKTstate0 + here->HICUMixf_Vbici);
Ixf_Vxf = *(ckt->CKTstate0 + here->HICUMixf_Vxf);
Ixf_Vrth = *(ckt->CKTstate0 + here->HICUMixf_Vrth);
////////////////////////////////////
////////// The real part /////////
////////////////////////////////////
// Stamp element: Ibiei
*(here->HICUMbaseBIBaseBIPtr) += Ibiei_Vbiei;
*(here->HICUMemitEIEmitEIPtr) += Ibiei_Vbiei;
*(here->HICUMbaseBIEmitEIPtr) += -Ibiei_Vbiei;
*(here->HICUMemitEIBaseBIPtr) += -Ibiei_Vbiei;
*(here->HICUMbaseBIBaseBIPtr) += Ibiei_Vbici;
*(here->HICUMemitEICollCIPtr) += Ibiei_Vbici;
*(here->HICUMbaseBICollCIPtr) += -Ibiei_Vbici;
*(here->HICUMemitEIBaseBIPtr) += -Ibiei_Vbici;
// Stamp element: Ibpei
*(here->HICUMbaseBPBaseBPPtr) += Ibpei_Vbpei;
*(here->HICUMemitEIEmitEIPtr) += Ibpei_Vbpei;
*(here->HICUMbaseBPEmitEIPtr) += -Ibpei_Vbpei;
*(here->HICUMemitEIBaseBPPtr) += -Ibpei_Vbpei;;
// Stamp element: Ibici
*(here->HICUMbaseBIBaseBIPtr) += Ibici_Vbici;
*(here->HICUMcollCICollCIPtr) += Ibici_Vbici;
*(here->HICUMcollCIBaseBIPtr) += -Ibici_Vbici;
*(here->HICUMbaseBICollCIPtr) += -Ibici_Vbici;
*(here->HICUMbaseBIBaseBIPtr) += Ibici_Vbiei;
*(here->HICUMcollCIEmitEIPtr) += Ibici_Vbiei;
*(here->HICUMcollCIBaseBIPtr) += -Ibici_Vbiei;
*(here->HICUMbaseBIEmitEIPtr) += -Ibici_Vbiei;
// Stamp element: Iciei
*(here->HICUMcollCIBaseBIPtr) += Iciei_Vbiei;
*(here->HICUMemitEIEmitEIPtr) += Iciei_Vbiei;
*(here->HICUMcollCIEmitEIPtr) += -Iciei_Vbiei;
*(here->HICUMemitEIBaseBIPtr) += -Iciei_Vbiei;
*(here->HICUMcollCIBaseBIPtr) += Iciei_Vbici;
*(here->HICUMemitEICollCIPtr) += Iciei_Vbici;
*(here->HICUMcollCICollCIPtr) += -Iciei_Vbici;
*(here->HICUMemitEIBaseBIPtr) += -Iciei_Vbici;
if (nqs) {
*(here->HICUMcollCIXf2Ptr) += Iciei_Vxf2;
*(here->HICUMemitEIXf2Ptr) += -Iciei_Vxf2;
}
// Stamp element: Ibpci
*(here->HICUMbaseBPBaseBPPtr) += Ibpci_Vbpci;
*(here->HICUMcollCICollCIPtr) += Ibpci_Vbpci;
*(here->HICUMbaseBPCollCIPtr) += -Ibpci_Vbpci;
*(here->HICUMcollCIBaseBPPtr) += -Ibpci_Vbpci;
// Stamp element: Rcx
*(here->HICUMcollCollPtr) += Icic_Vcic;
*(here->HICUMcollCICollCIPtr) += Icic_Vcic;
*(here->HICUMcollCICollPtr) += -Icic_Vcic;
*(here->HICUMcollCollCIPtr) += -Icic_Vcic;
// Stamp element: Rbx
*(here->HICUMbaseBasePtr) += Ibbp_Vbbp;
*(here->HICUMbaseBPBaseBPPtr) += Ibbp_Vbbp;
*(here->HICUMbaseBPBasePtr) += -Ibbp_Vbbp;
*(here->HICUMbaseBaseBPPtr) += -Ibbp_Vbbp;
// Stamp element: Re
*(here->HICUMemitEmitPtr) += Ieie_Veie;
*(here->HICUMemitEIEmitEIPtr) += Ieie_Veie;
*(here->HICUMemitEIEmitPtr) += -Ieie_Veie;
*(here->HICUMemitEmitEIPtr) += -Ieie_Veie;
// Stamp element: Ibpbi
if (here->HICUMrbi>0.0) {
*(here->HICUMbaseBPBaseBPPtr) += Ibpbi_Vbpbi;
*(here->HICUMbaseBIBaseBIPtr) += Ibpbi_Vbpbi;
*(here->HICUMbaseBPBaseBIPtr) += -Ibpbi_Vbpbi;
*(here->HICUMbaseBIBaseBPPtr) += -Ibpbi_Vbpbi;
*(here->HICUMbaseBPBaseBIPtr) += Ibpbi_Vbiei;
*(here->HICUMbaseBIEmitEIPtr) += Ibpbi_Vbiei;
*(here->HICUMbaseBPEmitEIPtr) += -Ibpbi_Vbiei;
*(here->HICUMbaseBIBaseBIPtr) += -Ibpbi_Vbiei;
*(here->HICUMbaseBPBaseBIPtr) += Ibpbi_Vbici;
*(here->HICUMbaseBICollCIPtr) += Ibpbi_Vbici;
*(here->HICUMbaseBPCollCIPtr) += -Ibpbi_Vbici;
*(here->HICUMbaseBIBaseBIPtr) += -Ibpbi_Vbici;
};
// Stamp element: Isici
*(here->HICUMsubsSISubsSIPtr) += Isici_Vsici;
*(here->HICUMcollCICollCIPtr) += Isici_Vsici;
*(here->HICUMsubsSICollCIPtr) += -Isici_Vsici;
*(here->HICUMcollCISubsSIPtr) += -Isici_Vsici;;
// Stamp element: Ibpsi
*(here->HICUMbaseBPSubsSIPtr) += Ibpsi_Vsici;
*(here->HICUMsubsSICollCIPtr) += Ibpsi_Vsici;
*(here->HICUMbaseBPCollCIPtr) += -Ibpsi_Vsici;
*(here->HICUMsubsSISubsSIPtr) += -Ibpsi_Vsici;
*(here->HICUMbaseBPBaseBPPtr) += Ibpsi_Vbpci;
*(here->HICUMsubsSICollCIPtr) += Ibpsi_Vbpci;
*(here->HICUMbaseBPCollCIPtr) += -Ibpsi_Vbpci;
*(here->HICUMsubsSIBaseBPPtr) += -Ibpsi_Vbpci;;
// Stamp element: Rsu
*(here->HICUMsubsSubsPtr) += Isis_Vsis;
*(here->HICUMsubsSISubsSIPtr) += Isis_Vsis;
*(here->HICUMsubsSISubsPtr) += -Isis_Vsis;
*(here->HICUMsubsSubsSIPtr) += -Isis_Vsis;
if (nqs) {
//Ixf1
*(here->HICUMxf1BaseBIPtr) += +Ixf1_Vbiei;
*(here->HICUMxf1EmitEIPtr) += -Ixf1_Vbiei;
*(here->HICUMxf1BaseBIPtr) += +Ixf1_Vbici;
*(here->HICUMxf1CollCIPtr) += -Ixf1_Vbici;
*(here->HICUMxf1Xf2Ptr) += +Ixf1_Vxf2;
*(here->HICUMxf1Xf1Ptr) += +Ixf1_Vxf1;
//Ixf2
*(here->HICUMxf2BaseBIPtr) += +Ixf2_Vbiei;
*(here->HICUMxf2EmitEIPtr) += -Ixf2_Vbiei;
*(here->HICUMxf2BaseBIPtr) += +Ixf2_Vbici;
*(here->HICUMxf2CollCIPtr) += -Ixf2_Vbici;
*(here->HICUMxf2Xf2Ptr) += +Ixf2_Vxf2;
*(here->HICUMxf2Xf1Ptr) += +Ixf2_Vxf1;
//Ixf
*(here->HICUMxfBaseBIPtr) += +Ixf_Vbiei;
*(here->HICUMxfEmitEIPtr) += -Ixf_Vbiei;
*(here->HICUMxfBaseBIPtr) += +Ixf_Vbici;
*(here->HICUMxfCollCIPtr) += -Ixf_Vbici;
*(here->HICUMxfXfPtr) += +Ixf_Vxf;
}
////////////////////////////////////
////////// The complex part //////
////////////////////////////////////
//Qrbi
XQrbi_Vbpbi = *(ckt->CKTstate0 + here->HICUMcqrbi) * ckt->CKTomega;
XQrbi_Vbiei = here->HICUMqrbi_Vbiei * ckt->CKTomega;
XQrbi_Vbici = here->HICUMqrbi_Vbici * ckt->CKTomega;
XQrbi_Vrth = here->HICUMqrbi_Vrth * ckt->CKTomega;
//Qjei
XQjei_Vbiei = *(ckt->CKTstate0 + here->HICUMcqjei) * ckt->CKTomega;
XQjei_Vrth = here->HICUMqjei_Vrth * ckt->CKTomega;
//Qf
XQf_Vbiei = *(ckt->CKTstate0 + here->HICUMcqf) * ckt->CKTomega;
XQf_Vbici = here->HICUMqf_Vbici * ckt->CKTomega;
XQf_Vrth = here->HICUMqf_Vrth * ckt->CKTomega;
XQf_Vxf = here->HICUMqf_Vxf * ckt->CKTomega;
//Qr
XQr_Vbici = *(ckt->CKTstate0 + here->HICUMcqr) * ckt->CKTomega;
XQr_Vbiei = here->HICUMqr_Vbiei * ckt->CKTomega;
XQr_Vrth = here->HICUMqr_Vrth * ckt->CKTomega;
//Qjci
XQjci_Vbici = *(ckt->CKTstate0 + here->HICUMcqjci) * ckt->CKTomega;
XQjci_Vrth = here->HICUMqjci_Vrth * ckt->CKTomega;
//Qjep
XQjep_Vbpei = *(ckt->CKTstate0 + here->HICUMcqjep) * ckt->CKTomega;
XQjep_Vrth = here->HICUMqjep_Vrth * ckt->CKTomega;
//Qjcx_i
Xqjcx0_t_i_Vbci = *(ckt->CKTstate0 + here->HICUMcqcx0_t_i) * ckt->CKTomega;
Xqjcx0_t_i_Vrth = here->HICUMqjcx0_i_Vrth * ckt->CKTomega;
//Qjcx_ii
Xqjcx0_t_ii_Vbpci = *(ckt->CKTstate0 + here->HICUMcqcx0_t_ii) * ckt->CKTomega;
Xqjcx0_t_ii_Vrth = here->HICUMqjcx0_ii_Vrth * ckt->CKTomega;
//Qdsu
XQdsu_Vbpci = *(ckt->CKTstate0 + here->HICUMcqdsu) * ckt->CKTomega;
XQdsu_Vsici = here->HICUMqdsu_Vsici * ckt->CKTomega;
XQdsu_Vrth = here->HICUMqdsu_Vrth * ckt->CKTomega;
//Qjs
XQjs_Vsici = *(ckt->CKTstate0 + here->HICUMcqjs) * ckt->CKTomega;
XQjs_Vrth = here->HICUMqjs_Vrth * ckt->CKTomega;
//Qscp
XQscp_Vsc = *(ckt->CKTstate0 + here->HICUMcqscp) * ckt->CKTomega;
XQscp_Vrth = here->HICUMqscp_Vrth * ckt->CKTomega;
//Qbepar1
XQbepar1_Vbe = *(ckt->CKTstate0 + here->HICUMcqbepar1) * ckt->CKTomega;
//Qbepar2
XQbepar2_Vbpe = *(ckt->CKTstate0 + here->HICUMcqbepar2) * ckt->CKTomega;
//Qbcpar1
XQbcpar1_Vbci = *(ckt->CKTstate0 + here->HICUMcqbcpar1) * ckt->CKTomega;
//Qbcpar2
XQbcpar2_Vbpci = *(ckt->CKTstate0 + here->HICUMcqbcpar2) * ckt->CKTomega;
//Qsu
XQsu_Vsis = *(ckt->CKTstate0 + here->HICUMcqsu) * ckt->CKTomega;
//Qcth
XQcth_Vrth = *(ckt->CKTstate0 + here->HICUMcqcth) * ckt->CKTomega;
//Qxf
XQxf_Vxf = *(ckt->CKTstate0 + here->HICUMcqxf) * ckt->CKTomega;
XQxf1_Vxf1 = *(ckt->CKTstate0 + here->HICUMcqxf1) * ckt->CKTomega;
XQxf2_Vxf2 = *(ckt->CKTstate0 + here->HICUMcqxf2) * ckt->CKTomega;
//Qrbi f_bp=+ f_bi=-
if (here->HICUMrbi>0.0) {
*(here->HICUMbaseBPBaseBPPtr + 1) += XQrbi_Vbpbi;
*(here->HICUMbaseBIBaseBIPtr + 1) += XQrbi_Vbpbi;
*(here->HICUMbaseBPBaseBIPtr + 1) += -XQrbi_Vbpbi;
*(here->HICUMbaseBIBaseBPPtr + 1) += -XQrbi_Vbpbi;
*(here->HICUMbaseBPBaseBIPtr + 1) += XQrbi_Vbiei;
*(here->HICUMbaseBIEmitEIPtr + 1) += XQrbi_Vbiei;
*(here->HICUMbaseBPEmitEIPtr + 1) += -XQrbi_Vbiei;
*(here->HICUMbaseBIBaseBIPtr + 1) += -XQrbi_Vbiei;
*(here->HICUMbaseBPBaseBIPtr + 1) += XQrbi_Vbici;
*(here->HICUMbaseBICollCIPtr + 1) += XQrbi_Vbici;
*(here->HICUMbaseBPCollCIPtr + 1) += -XQrbi_Vbici;
*(here->HICUMbaseBIBaseBIPtr + 1) += -XQrbi_Vbici;
}
//Qjei
*(here->HICUMbaseBIBaseBIPtr + 1) += XQjei_Vbiei;
*(here->HICUMemitEIEmitEIPtr + 1) += XQjei_Vbiei;
*(here->HICUMbaseBIEmitEIPtr + 1) += -XQjei_Vbiei;
*(here->HICUMemitEIBaseBIPtr + 1) += -XQjei_Vbiei;
//Qf f_Bi=+ f_Ei =-
*(here->HICUMbaseBIBaseBIPtr +1) += XQf_Vbiei;
*(here->HICUMemitEIEmitEIPtr +1) += XQf_Vbiei;
*(here->HICUMbaseBIEmitEIPtr +1) += -XQf_Vbiei;
*(here->HICUMemitEIBaseBIPtr +1) += -XQf_Vbiei;
*(here->HICUMbaseBIBaseBIPtr +1) += XQf_Vbici;
*(here->HICUMemitEICollCIPtr +1) += XQf_Vbici;
*(here->HICUMbaseBICollCIPtr +1) += -XQf_Vbici;
*(here->HICUMemitEIBaseBIPtr +1) += -XQf_Vbici;
if (nqs) {
*(here->HICUMbaseBIXfPtr +1) += XQf_Vxf;
*(here->HICUMemitEIXfPtr +1) += -XQf_Vxf;
}
//Qjci
*(here->HICUMbaseBIBaseBIPtr +1) += XQjci_Vbici;
*(here->HICUMcollCICollCIPtr +1) += XQjci_Vbici;
*(here->HICUMcollCIBaseBIPtr +1) += -XQjci_Vbici;
*(here->HICUMbaseBICollCIPtr +1) += -XQjci_Vbici;
//Qr f_bi = + f_ci=-
*(here->HICUMbaseBIBaseBIPtr +1) += XQr_Vbici;
*(here->HICUMcollCICollCIPtr +1) += XQr_Vbici;
*(here->HICUMcollCIBaseBIPtr +1) += -XQr_Vbici;
*(here->HICUMbaseBICollCIPtr +1) += -XQr_Vbici;
*(here->HICUMbaseBIBaseBIPtr +1) += XQr_Vbiei;
*(here->HICUMcollCIEmitEIPtr +1) += XQr_Vbiei;
*(here->HICUMcollCIBaseBIPtr +1) += -XQr_Vbiei;
*(here->HICUMbaseBIEmitEIPtr +1) += -XQr_Vbiei;
//Qjep
*(here->HICUMbaseBPBaseBPPtr +1) += XQjep_Vbpei;
*(here->HICUMemitEIEmitEIPtr +1) += XQjep_Vbpei;
*(here->HICUMbaseBPEmitEIPtr +1) += -XQjep_Vbpei;
*(here->HICUMemitEIBaseBPPtr +1) += -XQjep_Vbpei;
//Qjcx_i
*(here->HICUMbaseBasePtr +1) += Xqjcx0_t_i_Vbci;
*(here->HICUMcollCICollCIPtr +1) += Xqjcx0_t_i_Vbci;
*(here->HICUMbaseCollCIPtr +1) += -Xqjcx0_t_i_Vbci;
*(here->HICUMcollCIBasePtr +1) += -Xqjcx0_t_i_Vbci;
//Qjcx_ii
*(here->HICUMbaseBPBaseBPPtr +1) += Xqjcx0_t_ii_Vbpci;
*(here->HICUMcollCICollCIPtr +1) += Xqjcx0_t_ii_Vbpci;
*(here->HICUMbaseBPCollCIPtr +1) += -Xqjcx0_t_ii_Vbpci;
*(here->HICUMcollCIBaseBPPtr +1) += -Xqjcx0_t_ii_Vbpci;
//Qdsu f_bp=+ f_ci=-
*(here->HICUMbaseBPBaseBPPtr +1) += XQdsu_Vbpci;
*(here->HICUMcollCICollCIPtr +1) += XQdsu_Vbpci;
*(here->HICUMbaseBPCollCIPtr +1) += -XQdsu_Vbpci;
*(here->HICUMcollCIBaseBPPtr +1) += -XQdsu_Vbpci;
*(here->HICUMbaseBPSubsSIPtr +1) += XQdsu_Vsici;
*(here->HICUMcollCICollCIPtr +1) += XQdsu_Vsici;
*(here->HICUMbaseBPCollCIPtr +1) += -XQdsu_Vsici;
*(here->HICUMcollCISubsSIPtr +1) += -XQdsu_Vsici;
//Qjs
*(here->HICUMsubsSISubsSIPtr +1) += XQjs_Vsici;
*(here->HICUMcollCICollCIPtr +1) += XQjs_Vsici;
*(here->HICUMsubsSICollCIPtr +1) += -XQjs_Vsici;
*(here->HICUMcollCISubsSIPtr +1) += -XQjs_Vsici;
//Qscp
*(here->HICUMsubsSubsPtr + 1) += XQscp_Vsc;
*(here->HICUMcollCollPtr + 1) += XQscp_Vsc;
*(here->HICUMcollSubsPtr + 1) += -XQscp_Vsc;
*(here->HICUMsubsCollPtr + 1) += -XQscp_Vsc;
//Qbepar1
*(here->HICUMbaseBasePtr + 1) += XQbepar1_Vbe;
*(here->HICUMemitEmitPtr + 1) += XQbepar1_Vbe;
*(here->HICUMbaseEmitPtr + 1) += -XQbepar1_Vbe;
*(here->HICUMemitBasePtr + 1) += -XQbepar1_Vbe;
//Qbepar2
*(here->HICUMbaseBPBaseBPPtr + 1) += XQbepar2_Vbpe;
*(here->HICUMemitEmitPtr + 1) += XQbepar2_Vbpe;
*(here->HICUMemitBaseBPPtr + 1) += -XQbepar2_Vbpe;
*(here->HICUMbaseBPEmitPtr + 1) += -XQbepar2_Vbpe;
//Qbcpar1
*(here->HICUMbaseBasePtr + 1) += XQbcpar1_Vbci;
*(here->HICUMcollCICollCIPtr + 1) += XQbcpar1_Vbci;
*(here->HICUMbaseCollCIPtr + 1) += -XQbcpar1_Vbci;
*(here->HICUMcollCIBasePtr + 1) += -XQbcpar1_Vbci;
//Qbcpar2
*(here->HICUMbaseBPBaseBPPtr +1) += XQbcpar2_Vbpci;
*(here->HICUMcollCICollCIPtr +1) += XQbcpar2_Vbpci;
*(here->HICUMbaseBPCollCIPtr +1) += -XQbcpar2_Vbpci;
*(here->HICUMcollCIBaseBPPtr +1) += -XQbcpar2_Vbpci;
//Qsu
*(here->HICUMsubsSubsPtr + 1) += XQsu_Vsis;
*(here->HICUMsubsSISubsSIPtr + 1) += XQsu_Vsis;
*(here->HICUMsubsSISubsPtr + 1) += -XQsu_Vsis;
*(here->HICUMsubsSubsSIPtr + 1) += -XQsu_Vsis;
if (nqs) {
//Qxf1
*(here->HICUMxf1Xf1Ptr + 1) += +XQxf1_Vxf1;
//Qxf2
*(here->HICUMxf2Xf2Ptr + 1) += +XQxf2_Vxf2;
//Qxf
*(here->HICUMxfXfPtr + 1) += +XQxf_Vxf;
}
// Stamps with SH
if (selfheat) {
// Stamp element: Ibiei f_Bi = + f_Ei = -
*(here->HICUMbaseBItempPtr) += Ibiei_Vrth;
*(here->HICUMemitEItempPtr) += -Ibiei_Vrth;
// Stamp element: Ibpei f_Bp = + f_Ei = -
// with respect to Potential Vrth
*(here->HICUMbaseBPtempPtr) += Ibpei_Vrth;
*(here->HICUMemitEItempPtr) += -Ibpei_Vrth;
// Stamp element: Ibici f_Bi = + f_Ci = -
*(here->HICUMbaseBItempPtr) += Ibici_Vrth;
*(here->HICUMcollCItempPtr) += -Ibici_Vrth;
// Stamp element: Iciei f_Ci = + f_Ei = -
*(here->HICUMcollCItempPtr) += Iciei_Vrth;
*(here->HICUMemitEItempPtr) += -Iciei_Vrth;
// Stamp element: Ibpci f_Bp = + f_Ci = -
*(here->HICUMbaseBPtempPtr) += Ibpci_Vrth;
*(here->HICUMcollCItempPtr) += -Ibpci_Vrth;
// Stamp element: Rcx f_Ci = + f_C = -
*(here->HICUMcollCItempPtr) += Icic_Vrth;
*(here->HICUMcollTempPtr) += -Icic_Vrth;
// Stamp element: Rbx f_B = + f_Bp = -
*(here->HICUMbaseTempPtr) += Ibbp_Vrth;
*(here->HICUMbaseBPtempPtr) += -Ibbp_Vrth;
// Stamp element: Re f_Ei = + f_E = -
*(here->HICUMemitEItempPtr) += Ieie_Vrth;
*(here->HICUMemitTempPtr) += -Ieie_Vrth;
// Stamp element: Rbi f_Bp = + f_Bi = -
*(here->HICUMbaseBPtempPtr) += Ibpbi_Vrth;
*(here->HICUMbaseBItempPtr) += -Ibpbi_Vrth;
// Stamp element: Isici f_Si = + f_Ci = -
*(here->HICUMsubsSItempPtr) += Isici_Vrth;
*(here->HICUMcollCItempPtr) += -Isici_Vrth;
// Branch: bpsi, Stamp element: Its
*(here->HICUMbaseBPtempPtr) += Ibpsi_Vrth;
*(here->HICUMsubsSItempPtr) += -Ibpsi_Vrth;
if (nqs) {
// Stamp element: Ixf f_xf = +
*(here->HICUMxfTempPtr) += Ixf_Vrth;
// Stamp element: Ixf1 f_xf1 = +
*(here->HICUMxf1TempPtr) += Ixf1_Vrth;
// Stamp element: Ixf2 f_xf2 = +
*(here->HICUMxf2TempPtr) += Ixf2_Vrth;
}
// Stamp element: Rth f_T = +
*(here->HICUMtempTempPtr) += Irth_Vrth;
// Stamp element: Ith f_T = - Ith
// with respect to Potential Vrth
*(here->HICUMtempTempPtr) += -Ith_Vrth;
// with respect to Potential Vbiei
*(here->HICUMtempBaseBIPtr) += -Ith_Vbiei;
*(here->HICUMtempEmitEIPtr) += +Ith_Vbiei;
// with respect to Potential Vbici
*(here->HICUMtempBaseBIPtr) += -Ith_Vbici;
*(here->HICUMtempCollCIPtr) += +Ith_Vbici;
// with respect to Potential Vciei
*(here->HICUMtempCollCIPtr) += -Ith_Vciei;
*(here->HICUMtempEmitEIPtr) += +Ith_Vciei;
// with respect to Potential Vbpei
*(here->HICUMtempBaseBPPtr) += -Ith_Vbpei;
*(here->HICUMtempEmitEIPtr) += +Ith_Vbpei;
// with respect to Potential Vbpci
*(here->HICUMtempBaseBPPtr) += -Ith_Vbpci;
*(here->HICUMtempCollCIPtr) += +Ith_Vbpci;
// with respect to Potential Vsici
*(here->HICUMtempSubsSIPtr) += -Ith_Vsici;
*(here->HICUMtempCollCIPtr) += +Ith_Vsici;
// with respect to Potential Vbpbi
*(here->HICUMtempBaseBPPtr) += -Ith_Vbpbi;
*(here->HICUMtempBaseBIPtr) += +Ith_Vbpbi;
// with respect to Potential Vcic
*(here->HICUMtempCollCIPtr) += -Ith_Vcic;
*(here->HICUMtempCollPtr) += +Ith_Vcic;
// with respect to Potential Vbbp
*(here->HICUMtempBasePtr) += -Ith_Vbbp;
*(here->HICUMtempBaseBPPtr) += +Ith_Vbbp;
// with respect to Potential Veie
*(here->HICUMtempEmitEIPtr) += -Ith_Veie;
*(here->HICUMtempEmitPtr) += +Ith_Veie;
//the charges
*(here->HICUMbaseBItempPtr + 1) += +XQrbi_Vrth;
*(here->HICUMbaseBPtempPtr + 1) += -XQrbi_Vrth;
*(here->HICUMbaseBItempPtr + 1) += +XQjei_Vrth;
*(here->HICUMemitEItempPtr + 1) += -XQjei_Vrth;
*(here->HICUMbaseBItempPtr + 1) += +XQf_Vrth;
*(here->HICUMemitEItempPtr + 1) += -XQf_Vrth;
*(here->HICUMbaseBItempPtr + 1) += +XQr_Vrth;
*(here->HICUMcollCItempPtr + 1) += -XQr_Vrth;
*(here->HICUMbaseBItempPtr + 1) += +XQjci_Vrth;
*(here->HICUMcollCItempPtr + 1) += -XQjci_Vrth;
*(here->HICUMbaseBPtempPtr + 1) += +XQjep_Vrth;
*(here->HICUMemitEItempPtr + 1) += -XQjep_Vrth;
*(here->HICUMbaseTempPtr + 1) += +Xqjcx0_t_i_Vrth;
*(here->HICUMcollCItempPtr + 1) += -Xqjcx0_t_i_Vrth;
*(here->HICUMbaseBPtempPtr + 1) += +Xqjcx0_t_ii_Vrth;
*(here->HICUMcollCItempPtr + 1) += -Xqjcx0_t_ii_Vrth;
*(here->HICUMbaseBPtempPtr + 1) += +XQdsu_Vrth;
*(here->HICUMcollCItempPtr + 1) += -XQdsu_Vrth;
*(here->HICUMsubsSItempPtr + 1) += +XQjs_Vrth;
*(here->HICUMcollCItempPtr + 1) += -XQjs_Vrth;
*(here->HICUMsubsTempPtr + 1) += +XQscp_Vrth;
*(here->HICUMcollTempPtr + 1) += -XQscp_Vrth;
*(here->HICUMtempTempPtr + 1) += +XQcth_Vrth;
}
}
}
return(OK);
}

251
src/spicelib/devices/hicum2/hicum2ask.c

@ -0,0 +1,251 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine gives access to the internal device
* parameters for HICUMs
*/
#include "ngspice/ngspice.h"
#include "ngspice/const.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/ifsim.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
/*ARGSUSED*/
int
HICUMask(CKTcircuit *ckt, GENinstance *instPtr, int which, IFvalue *value, IFvalue *select)
{
HICUMinstance *here = (HICUMinstance*)instPtr;
NG_IGNORE(select);
double g_be;
IFvalue IC, IB, RPIi, RPIx, GMi;
IFvalue CPIi, CPIx, CMUi, CMUx;
IFvalue rcx_t, re_t, rb, BETAAC;
switch(which) {
case HICUM_AREA:
value->rValue = here->HICUMarea;
return(OK);
case HICUM_OFF:
value->iValue = here->HICUMoff;
return(OK);
case HICUM_TEMP:
value->rValue = here->HICUMtemp - CONSTCtoK;
return(OK);
case HICUM_M:
value->rValue = here->HICUMm;
return(OK);
case HICUM_QUEST_COLLNODE:
value->iValue = here->HICUMcollNode;
return(OK);
case HICUM_QUEST_BASENODE:
value->iValue = here->HICUMbaseNode;
return(OK);
case HICUM_QUEST_EMITNODE:
value->iValue = here->HICUMemitNode;
return(OK);
case HICUM_QUEST_SUBSNODE:
value->iValue = here->HICUMsubsNode;
return(OK);
case HICUM_QUEST_COLLCINODE:
value->iValue = here->HICUMcollCINode;
return(OK);
case HICUM_QUEST_BASEBPNODE:
value->iValue = here->HICUMbaseBPNode;
return(OK);
case HICUM_QUEST_BASEBINODE:
value->iValue = here->HICUMbaseBINode;
return(OK);
case HICUM_QUEST_EMITEINODE:
value->iValue = here->HICUMemitEINode;
return(OK);
case HICUM_QUEST_SUBSSINODE:
value->iValue = here->HICUMsubsSINode;
return(OK);
/* voltages */
case HICUM_QUEST_VBE:
value->rValue = *(ckt->CKTstate0 + here->HICUMbaseNode)-*(ckt->CKTstate0 + here->HICUMemitNode);
return(OK);
case HICUM_QUEST_VBBP:
value->rValue = *(ckt->CKTstate0 + here->HICUMbaseNode)-*(ckt->CKTstate0 + here->HICUMbaseBPNode);
return(OK);
case HICUM_QUEST_VBC:
value->rValue = *(ckt->CKTstate0 + here->HICUMbaseNode)-*(ckt->CKTstate0 + here->HICUMcollNode);
return(OK);
case HICUM_QUEST_VCE:
value->rValue = *(ckt->CKTstate0 + here->HICUMcollNode)-*(ckt->CKTstate0 + here->HICUMemitNode);
return(OK);
case HICUM_QUEST_VSC:
value->rValue = *(ckt->CKTstate0 + here->HICUMcollNode)-*(ckt->CKTstate0 + here->HICUMsubsNode);
return(OK);
case HICUM_QUEST_VBIEI:
value->rValue = *(ckt->CKTstate0 + here->HICUMvbiei);
return(OK);
case HICUM_QUEST_VBPBI:
value->rValue = *(ckt->CKTstate0 + here->HICUMvbpbi);
return(OK);
case HICUM_QUEST_VBICI:
value->rValue = *(ckt->CKTstate0 + here->HICUMvbici);
return(OK);
case HICUM_QUEST_VCIEI:
value->rValue = *(ckt->CKTstate0 + here->HICUMvbiei) - *(ckt->CKTstate0 + here->HICUMvbici);
return(OK);
/* currents */
case HICUM_QUEST_CC:
// value->rValue = 0.0;
value->rValue = *(ckt->CKTstate0 + here->HICUMiciei) -
*(ckt->CKTstate0 + here->HICUMibici) -
*(ckt->CKTstate0 + here->HICUMibpci) -
*(ckt->CKTstate0 + here->HICUMisici);
return(OK);
case HICUM_QUEST_CB:
value->rValue = *(ckt->CKTstate0 + here->HICUMibiei) +
*(ckt->CKTstate0 + here->HICUMibici) +
*(ckt->CKTstate0 + here->HICUMibpci) +
*(ckt->CKTstate0 + here->HICUMibpsi);
return(OK);
case HICUM_QUEST_CE:
value->rValue = - *(ckt->CKTstate0 + here->HICUMibiei) -
*(ckt->CKTstate0 + here->HICUMibpei) -
*(ckt->CKTstate0 + here->HICUMiciei);
return(OK);
case HICUM_QUEST_CS:
value->rValue = *(ckt->CKTstate0 + here->HICUMisici) -
*(ckt->CKTstate0 + here->HICUMibpsi);
return(OK);
case HICUM_QUEST_CAVL:
value->rValue = here->HICUMiavl;
return(OK);
case HICUM_QUEST_CBEI:
value->rValue = *(ckt->CKTstate0 + here->HICUMibiei);
return(OK);
case HICUM_QUEST_CBCI:
value->rValue = *(ckt->CKTstate0 + here->HICUMibici);
return(OK);
/* resistances */
case HICUM_QUEST_RCX_T:
value->rValue = here->HICUMrcx_t.rpart;
return(OK);
case HICUM_QUEST_RE_T:
value->rValue = here->HICUMre_t.rpart;
return(OK);
case HICUM_QUEST_IT:
value->rValue = *(ckt->CKTstate0 + here->HICUMiciei);
return(OK);
case HICUM_QUEST_RBI:
value->rValue = here->HICUMrbi;
return(OK);
case HICUM_QUEST_RB:
value->rValue = here->HICUMrbi + here->HICUMrbx_t.rpart;
return(OK);
/* transconductances and capacitances */
case HICUM_QUEST_BETADC:
HICUMask(ckt, instPtr, HICUM_QUEST_CC, &IC, select);
HICUMask(ckt, instPtr, HICUM_QUEST_CB, &IB, select);
if (IB.rValue != 0.0) {
value->rValue = IC.rValue/IB.rValue;
} else {
value->rValue = 0.0;
}
return(OK);
case HICUM_QUEST_GMI:
value->rValue = *(ckt->CKTstate0 + here->HICUMiciei_Vbiei);
return(OK);
case HICUM_QUEST_GMS:
value->rValue = *(ckt->CKTstate0 + here->HICUMibpsi_Vbpci);
return(OK);
case HICUM_QUEST_RPII:
value->rValue = 1/( *(ckt->CKTstate0 + here->HICUMibiei_Vbiei) );
return(OK);
case HICUM_QUEST_RPIX:
value->rValue = 1/( *(ckt->CKTstate0 + here->HICUMibpei_Vbpei) );
return(OK);
case HICUM_QUEST_RMUI:
value->rValue = 1/( *(ckt->CKTstate0 + here->HICUMibici_Vbici) + ckt->CKTgmin);
return(OK);
case HICUM_QUEST_RMUX:
value->rValue = 1/( *(ckt->CKTstate0 + here->HICUMibpci_Vbpci) + ckt->CKTgmin);
return(OK);
case HICUM_QUEST_ROI:
value->rValue = 1/( *(ckt->CKTstate0 + here->HICUMiciei_Vbiei) + ckt->CKTgmin);
return(OK);
case HICUM_QUEST_CPII:
value->rValue = here->HICUMcapjei + here->HICUMcapdeix;
return(OK);
case HICUM_QUEST_CPIX:
value->rValue = here->HICUMcapjep + here->HICUMcbepar_scaled;
return(OK);
case HICUM_QUEST_CMUI:
value->rValue = here->HICUMcapjci + here->HICUMcapdci;
return(OK);
case HICUM_QUEST_CMUX:
value->rValue = here->HICUMcapjcx_t_i + here->HICUMcapjcx_t_ii + here->HICUMcbcpar_scaled + here->HICUMcapdsu;
return(OK);
case HICUM_QUEST_CCS:
value->rValue = here->HICUMcapjs + here->HICUMcapscp;
return(OK);
case HICUM_QUEST_CRBI:
value->rValue = here->HICUMcaprbi;
return(OK);
case HICUM_QUEST_BETAAC:
HICUMask(ckt, instPtr, HICUM_QUEST_RPII, &RPIi, select);
HICUMask(ckt, instPtr, HICUM_QUEST_RPIX, &RPIx, select);
HICUMask(ckt, instPtr, HICUM_QUEST_GMI, &GMi, select);
g_be = 1/(RPIi.rValue + RPIx.rValue);
if (g_be > 0.0) {
value->rValue = GMi.rValue/g_be;
} else {
value->rValue = 0.0;
}
return(OK);
/* transit time */
case HICUM_QUEST_TF:
value->rValue = here->HICUMtf;
return(OK);
case HICUM_QUEST_FT:
// FT = GMi/(2*`M_PI*(CPIi+CPIx+CMUi+CMUx+(rcx_t+re_t+(re_t+rb)/BETAAC)*GMi*(CMUi+CMUx)));
HICUMask(ckt, instPtr, HICUM_QUEST_GMI, &GMi, select);
HICUMask(ckt, instPtr, HICUM_QUEST_CPII, &CPIi, select);
HICUMask(ckt, instPtr, HICUM_QUEST_CPIX, &CPIx, select);
HICUMask(ckt, instPtr, HICUM_QUEST_CMUI, &CMUi, select);
HICUMask(ckt, instPtr, HICUM_QUEST_CMUX, &CMUx, select);
HICUMask(ckt, instPtr, HICUM_QUEST_RCX_T, &rcx_t, select);
HICUMask(ckt, instPtr, HICUM_QUEST_RE_T, &re_t, select);
HICUMask(ckt, instPtr, HICUM_QUEST_RB, &rb, select);
HICUMask(ckt, instPtr, HICUM_QUEST_BETAAC, &BETAAC, select);
value->rValue = GMi.rValue/(
2 * M_PI * (
CPIi.rValue + CPIx.rValue +
CMUi.rValue + CMUx.rValue +
(rcx_t.rValue + re_t.rValue + (re_t.rValue + rb.rValue)/BETAAC.rValue)
) * GMi.rValue * (
CMUi.rValue + CMUx.rValue
)
);
return(OK);
case HICUM_QUEST_ICK:
value->rValue = here->HICUMick;
return(OK);
case HICUM_QUEST_POWER:
value->rValue = here->HICUMpterm;
return(OK);
case HICUM_QUEST_TK:
value->rValue = here->HICUMtemp;
return(OK);
case HICUM_QUEST_DTSH:
value->rValue = here->HICUMdtemp_sh;
return(OK);
default:
return(E_BADPARM);
}
/* NOTREACHED */
}

221
src/spicelib/devices/hicum2/hicum2conv.c

@ -0,0 +1,221 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine performs the device convergence test for
* HICUMs in the circuit.
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
HICUMconvTest(GENmodel *inModel, CKTcircuit *ckt)
{
HICUMinstance *here;
HICUMmodel *model = (HICUMmodel *) inModel;
double tol;
double delvbiei;
double delvbici;
double delvbpei;
double delvbpbi;
double delvbpci;
double delvsici;
double delvrth;
double delvciei;
double delvcic;
double delvbbp;
double delveie;
double ibieihat;
double ibicihat;
double icieihat;
double ibpeihat;
double ibpbihat;
double ibpcihat;
double ibpsihat;
double isicihat;
double volatile ithhat;
double Vbiei, Vbici, Vciei, Vbpei, Vbpbi, Vbpci, Vbci, Vsici, Vrth, Vcic, Vbbp, Veie;
double Ibiei, Ibici, Iciei, Ibpei, Ibpbi, Ibpci, Ibpsi, Isici, Ith;
for( ; model != NULL; model = HICUMnextModel(model)) {
for(here=HICUMinstances(model);here!=NULL;here = HICUMnextInstance(here)) {
Vbci = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseNode)-
*(ckt->CKTrhsOld+here->HICUMcollCINode));
Vbiei= model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseBINode)-
*(ckt->CKTrhsOld+here->HICUMemitEINode));
Vbici = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseBINode)-
*(ckt->CKTrhsOld+here->HICUMcollCINode));
Vbpei = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseBPNode)-
*(ckt->CKTrhsOld+here->HICUMemitEINode));
Vbpbi = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseBPNode)-
*(ckt->CKTrhsOld+here->HICUMbaseBINode));
Vbpci = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseBPNode)-
*(ckt->CKTrhsOld+here->HICUMcollCINode));
Vsici = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMsubsSINode)-
*(ckt->CKTrhsOld+here->HICUMcollCINode));
Vcic = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMcollCINode)-
*(ckt->CKTrhsOld+here->HICUMcollNode));
Vbbp = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMbaseNode)-
*(ckt->CKTrhsOld+here->HICUMbaseBPNode));
Veie = model->HICUMtype*(
*(ckt->CKTrhsOld+here->HICUMemitNode)-
*(ckt->CKTrhsOld+here->HICUMemitEINode));
Vciei = Vbiei - Vbici;
Vrth = model->HICUMtype*(*(ckt->CKTrhsOld+here->HICUMtempNode));
delvrth = Vrth - *(ckt->CKTstate0 + here->HICUMvrth);
delvbiei = Vbiei - *(ckt->CKTstate0 + here->HICUMvbiei);
delvbici = Vbici - *(ckt->CKTstate0 + here->HICUMvbici);
delvbpei = Vbpei - *(ckt->CKTstate0 + here->HICUMvbpei);
delvbpbi = Vbpbi - *(ckt->CKTstate0 + here->HICUMvbpbi);
delvbpci = Vbpci - *(ckt->CKTstate0 + here->HICUMvbpci);
delvsici = Vsici - *(ckt->CKTstate0 + here->HICUMvsici);
delvciei = delvbiei-delvbici;
delvcic = Vcic - *(ckt->CKTstate0 + here->HICUMvcic);
delvbbp = Vbbp - *(ckt->CKTstate0 + here->HICUMvbbp);
delveie = Veie - *(ckt->CKTstate0 + here->HICUMveie);
//todo: maybe add ibiei_Vxf
ibieihat = *(ckt->CKTstate0 + here->HICUMibiei) +
*(ckt->CKTstate0 + here->HICUMibiei_Vbiei)*delvbiei +
*(ckt->CKTstate0 + here->HICUMibiei_Vrth)*delvrth +
*(ckt->CKTstate0 + here->HICUMibiei_Vbici)*delvbici;
ibicihat = *(ckt->CKTstate0 + here->HICUMibici) +
*(ckt->CKTstate0 + here->HICUMibici_Vbici)*delvbici+
*(ckt->CKTstate0 + here->HICUMibici_Vrth)*delvrth+
*(ckt->CKTstate0 + here->HICUMibici_Vbiei)*delvbiei;
icieihat = *(ckt->CKTstate0 + here->HICUMiciei) +
*(ckt->CKTstate0 + here->HICUMiciei_Vbiei)*delvbiei +
*(ckt->CKTstate0 + here->HICUMiciei_Vrth)*delvrth +
*(ckt->CKTstate0 + here->HICUMiciei_Vbici)*delvbici;
ibpeihat = *(ckt->CKTstate0 + here->HICUMibpei) +
*(ckt->CKTstate0 + here->HICUMibpei_Vrth)*delvrth+
*(ckt->CKTstate0 + here->HICUMibpei_Vbpei)*delvbpei;
ibpbihat = *(ckt->CKTstate0 + here->HICUMibpbi) +
*(ckt->CKTstate0 + here->HICUMibpbi_Vbiei)*delvbiei +
*(ckt->CKTstate0 + here->HICUMibpbi_Vrth)*delvrth +
*(ckt->CKTstate0 + here->HICUMibpbi_Vbici)*delvbici;
ibpcihat = *(ckt->CKTstate0 + here->HICUMibpci) +
*(ckt->CKTstate0 + here->HICUMibpci_Vrth)*delvrth+
*(ckt->CKTstate0 + here->HICUMibpci_Vbpci)*delvbici;
ibpsihat = *(ckt->CKTstate0 + here->HICUMibpsi) +
*(ckt->CKTstate0 + here->HICUMibpsi_Vbpci)*delvbpci +
*(ckt->CKTstate0 + here->HICUMibpsi_Vrth)*delvrth +
*(ckt->CKTstate0 + here->HICUMibpsi_Vsici)*delvsici;
isicihat = *(ckt->CKTstate0 + here->HICUMisici) +
*(ckt->CKTstate0 + here->HICUMisici_Vrth)*delvrth+
*(ckt->CKTstate0 + here->HICUMisici_Vsici)*delvsici;
ithhat = *(ckt->CKTstate0 + here->HICUMith) +
*(ckt->CKTstate0 + here->HICUMith_Vrth)*delvrth+
*(ckt->CKTstate0 + here->HICUMith_Vbiei)*delvbiei+
*(ckt->CKTstate0 + here->HICUMith_Vbici)*delvbici+
*(ckt->CKTstate0 + here->HICUMith_Vbpbi)*delvbpbi+
*(ckt->CKTstate0 + here->HICUMith_Vbpci)*delvbpci+
*(ckt->CKTstate0 + here->HICUMith_Vbpei)*delvbpei+
*(ckt->CKTstate0 + here->HICUMith_Vciei)*delvciei+
*(ckt->CKTstate0 + here->HICUMith_Vsici)*delvsici+
*(ckt->CKTstate0 + here->HICUMith_Vcic)*delvcic+
*(ckt->CKTstate0 + here->HICUMith_Vbbp)*delvbbp+
*(ckt->CKTstate0 + here->HICUMith_Veie)*delveie;
Ibiei = *(ckt->CKTstate0 + here->HICUMibiei);
Ibici = *(ckt->CKTstate0 + here->HICUMibici);
Iciei = *(ckt->CKTstate0 + here->HICUMiciei);
Ibpei = *(ckt->CKTstate0 + here->HICUMibpei);
Ibpbi = *(ckt->CKTstate0 + here->HICUMibpbi);
Ibpci = *(ckt->CKTstate0 + here->HICUMibpci);
Ibpsi = *(ckt->CKTstate0 + here->HICUMibpsi);
Isici = *(ckt->CKTstate0 + here->HICUMisici);
Ith = *(ckt->CKTstate0 + here->HICUMith);
/*
* check convergence
*/
tol=ckt->CKTreltol*MAX(fabs(ibieihat),fabs(Ibiei))+ckt->CKTabstol;
if (fabs(ibieihat-Ibiei) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(ibicihat),fabs(Ibici))+ckt->CKTabstol;
if (fabs(ibicihat-Ibici) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(icieihat),fabs(Iciei))+ckt->CKTabstol;
if (fabs(icieihat-Iciei) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(ibpeihat),fabs(Ibpei))+ckt->CKTabstol;
if (fabs(ibpeihat-Ibpei) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(ibpbihat),fabs(Ibpbi))+ckt->CKTabstol;
if (fabs(ibpbihat-Ibpbi) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(ibpcihat),fabs(Ibpci))+ckt->CKTabstol;
if (fabs(ibpcihat-Ibpci) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(ibpsihat),fabs(Ibpsi))+ckt->CKTabstol;
if (fabs(ibpsihat-Ibpsi) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(isicihat),fabs(Isici))+ckt->CKTabstol;
if (fabs(isicihat-Isici) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
} else {
tol=ckt->CKTreltol*MAX(fabs(ithhat),fabs(Ith))+ckt->CKTabstol;
if (fabs(ithhat-Ith) > tol) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = (GENinstance *) here;
return(OK); /* no reason to continue - we've failed... */
}
}
}
}
}
}
}
}
}
}
}
return(OK);
}

1180
src/spicelib/devices/hicum2/hicum2defs.h
File diff suppressed because it is too large
View File

27
src/spicelib/devices/hicum2/hicum2ext.h

@ -0,0 +1,27 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#ifndef __HICUMEXT_H
#define __HICUMEXT_H
extern int HICUMacLoad(GENmodel *,CKTcircuit*);
extern int HICUMask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*);
extern int HICUMconvTest(GENmodel*,CKTcircuit*);
extern int HICUMdelete(GENinstance*);
extern int HICUMgetic(GENmodel*,CKTcircuit*);
//extern int HICUMload(GENmodel*,CKTcircuit*);//moved to hicumL2.hpp
extern int HICUMmAsk(CKTcircuit*,GENmodel*,int,IFvalue*);
extern int HICUMmParam(int,IFvalue*,GENmodel*);
extern int HICUMparam(int,IFvalue*,GENinstance*,IFvalue*);
extern int HICUMpzLoad(GENmodel*, CKTcircuit*, SPcomplex*);
extern int HICUMsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*);
extern int HICUMunsetup(GENmodel*,CKTcircuit*);
// extern int HICUMtemp(GENmodel*,CKTcircuit*); // moved to hicum2temp.hpp
extern int HICUMtrunc(GENmodel*,CKTcircuit*,double*);
extern int HICUMnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*);
extern int HICUMsoaCheck(CKTcircuit *, GENmodel *);
#endif

51
src/spicelib/devices/hicum2/hicum2getic.c

@ -0,0 +1,51 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine gets the device initial conditions for the HICUMs
* from the RHS vector
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
HICUMgetic(GENmodel *inModel, CKTcircuit *ckt)
{
HICUMmodel *model = (HICUMmodel*)inModel;
HICUMinstance *here;
/*
* grab initial conditions out of rhs array. User specified, so use
* external nodes to get values
*/
for( ; model ; model = HICUMnextModel(model)) {
for(here = HICUMinstances(model); here ; here = HICUMnextInstance(here)) {
if(!here->HICUMicVBEGiven) {
here->HICUMicVBE =
*(ckt->CKTrhs + here->HICUMbaseNode) -
*(ckt->CKTrhs + here->HICUMemitNode);
}
if(!here->HICUMicVCEGiven) {
here->HICUMicVCE =
*(ckt->CKTrhs + here->HICUMcollNode) -
*(ckt->CKTrhs + here->HICUMemitNode);
}
if(!here->HICUMicVCSGiven) {
here->HICUMicVCS =
*(ckt->CKTrhs + here->HICUMcollNode) -
*(ckt->CKTrhs + here->HICUMsubsNode);
}
}
}
return(OK);
}

85
src/spicelib/devices/hicum2/hicum2init.c

@ -0,0 +1,85 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#include "ngspice/config.h"
#include "ngspice/devdefs.h"
#include "hicum2itf.h"
#include "hicum2ext.h"
#include "hicum2init.h"
#include "hicumL2.hpp"
#include "hicumL2temp.hpp"
SPICEdev HICUMinfo = {
.DEVpublic = {
.name = "hicum2",
.description = "High Current Model for BJT",
.terms = &HICUMnSize,
.numNames = &HICUMnSize,
.termNames = HICUMnames,
.numInstanceParms = &HICUMpTSize,
.instanceParms = HICUMpTable,
.numModelParms = &HICUMmPTSize,
.modelParms = HICUMmPTable,
.flags = DEV_DEFAULT,
#ifdef XSPICE
.cm_func = NULL,
.num_conn = 0,
.conn = NULL,
.num_param = 0,
.param = NULL,
.num_inst_var = 0,
.inst_var = NULL,
#endif
},
.DEVparam = HICUMparam,
.DEVmodParam = HICUMmParam,
.DEVload = HICUMload,
.DEVsetup = HICUMsetup,
.DEVunsetup = HICUMunsetup,
.DEVpzSetup = HICUMsetup,
.DEVtemperature = HICUMtemp,
.DEVtrunc = HICUMtrunc,
.DEVfindBranch = NULL,
.DEVacLoad = HICUMacLoad,
.DEVaccept = NULL,
.DEVdestroy = NULL,
.DEVmodDelete = NULL,
.DEVdelete = NULL,
.DEVsetic = HICUMgetic,
.DEVask = HICUMask,
.DEVmodAsk = HICUMmAsk,
.DEVpzLoad = HICUMpzLoad,
.DEVconvTest = HICUMconvTest,
.DEVsenSetup = NULL,
.DEVsenLoad = NULL,
.DEVsenUpdate = NULL,
.DEVsenAcLoad = NULL,
.DEVsenPrint = NULL,
.DEVsenTrunc = NULL,
.DEVdisto = NULL,
.DEVnoise = HICUMnoise,
.DEVsoaCheck = HICUMsoaCheck,
.DEVinstSize = &HICUMiSize,
.DEVmodSize = &HICUMmSize,
#ifdef CIDER
.DEVdump = NULL,
.DEVacct = NULL,
#endif
};
SPICEdev *
get_hicum_info(void)
{
return &HICUMinfo;
}

20
src/spicelib/devices/hicum2/hicum2init.h

@ -0,0 +1,20 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#ifndef _HICUMINIT_H
#define _HICUMINIT_H
extern IFparm HICUMpTable[ ];
extern IFparm HICUMmPTable[ ];
extern char *HICUMnames[ ];
extern int HICUMpTSize;
extern int HICUMmPTSize;
extern int HICUMnSize;
extern int HICUMiSize;
extern int HICUMmSize;
#endif

11
src/spicelib/devices/hicum2/hicum2itf.h

@ -0,0 +1,11 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#ifndef DEV_HICUM
#define DEV_HICUM
extern SPICEdev *get_hicum_info(void);
#endif

460
src/spicelib/devices/hicum2/hicum2mask.c

@ -0,0 +1,460 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#include "ngspice/ngspice.h"
#include "ngspice/const.h"
#include "ngspice/ifsim.h"
#include "ngspice/cktdefs.h"
#include "ngspice/devdefs.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
#define MIN_R 0.001
/*ARGSUSED*/
int
HICUMmAsk(CKTcircuit *ckt, GENmodel *instPtr, int which, IFvalue *value)
{
HICUMmodel *model = (HICUMmodel*)instPtr;
NG_IGNORE(ckt);
switch(which) {
//Circuit simulator specific parameters
case HICUM_MOD_TYPE:
if (model->HICUMtype == NPN)
value->sValue = "npn";
else
value->sValue = "pnp";
return(OK);
case HICUM_MOD_TNOM:
value->rValue = model->HICUMtnom;
return(OK);
case HICUM_MOD_VERSION :
value->sValue = model->HICUMversion;
return(OK);
//Transfer current
case HICUM_MOD_C10:
value->rValue = model->HICUMc10;
return(OK);
case HICUM_MOD_QP0:
value->rValue = model->HICUMqp0;
return(OK);
case HICUM_MOD_ICH:
value->rValue = model->HICUMich;
return(OK);
case HICUM_MOD_HF0:
value->rValue = model->HICUMhf0;
return(OK);
case HICUM_MOD_HFE:
value->rValue = model->HICUMhfe;
return(OK);
case HICUM_MOD_HFC:
value->rValue = model->HICUMhfc;
return(OK);
case HICUM_MOD_HJEI:
value->rValue = model->HICUMhjei;
return(OK);
case HICUM_MOD_AHJEI:
value->rValue = model->HICUMahjei;
return(OK);
case HICUM_MOD_RHJEI:
value->rValue = model->HICUMrhjei;
return(OK);
case HICUM_MOD_HJCI:
value->rValue = model->HICUMhjci;
return(OK);
//Base-Emitter diode:
case HICUM_MOD_IBEIS:
value->rValue = model->HICUMibeis;
return(OK);
case HICUM_MOD_MBEI:
value->rValue = model->HICUMmbei;
return(OK);
case HICUM_MOD_IREIS:
value->rValue = model->HICUMireis;
return(OK);
case HICUM_MOD_MREI:
value->rValue = model->HICUMmrei;
return(OK);
case HICUM_MOD_IBEPS:
value->rValue = model->HICUMibeps;
return(OK);
case HICUM_MOD_MBEP:
value->rValue = model->HICUMmbep;
return(OK);
case HICUM_MOD_IREPS:
value->rValue = model->HICUMireps;
return(OK);
case HICUM_MOD_MREP:
value->rValue = model->HICUMmrep;
return(OK);
case HICUM_MOD_MCF:
value->rValue = model->HICUMmcf;
return(OK);
case HICUM_MOD_TBHREC:
value->rValue = model->HICUMtbhrec;
return(OK);
case HICUM_MOD_IBCIS:
value->rValue = model->HICUMibcis;
return(OK);
case HICUM_MOD_MBCI:
value->rValue = model->HICUMmbci;
return(OK);
case HICUM_MOD_IBCXS:
value->rValue = model->HICUMibcxs;
return(OK);
case HICUM_MOD_MBCX:
value->rValue = model->HICUMmbcx;
return(OK);
case HICUM_MOD_IBETS:
value->rValue = model->HICUMibets;
return(OK);
case HICUM_MOD_ABET:
value->rValue = model->HICUMabet;
return(OK);
case HICUM_MOD_TUNODE:
value->rValue = model->HICUMtunode = value->iValue;
return(OK);
case HICUM_MOD_FAVL:
value->rValue = model->HICUMfavl;
return(OK);
case HICUM_MOD_QAVL:
value->rValue = model->HICUMqavl;
return(OK);
case HICUM_MOD_KAVL:
value->rValue = model->HICUMkavl;
return(OK);
case HICUM_MOD_ALFAV:
value->rValue = model->HICUMalfav;
return(OK);
case HICUM_MOD_ALQAV:
value->rValue = model->HICUMalqav;
return(OK);
case HICUM_MOD_ALKAV:
value->rValue = model->HICUMalkav;
return(OK);
case HICUM_MOD_RBI0:
value->rValue = model->HICUMrbi0;
return(OK);
case HICUM_MOD_RBX:
value->rValue = model->HICUMrbx;
return(OK);
case HICUM_MOD_FGEO:
value->rValue = model->HICUMfgeo;
return(OK);
case HICUM_MOD_FDQR0:
value->rValue = model->HICUMfdqr0;
return(OK);
case HICUM_MOD_FCRBI:
value->rValue = model->HICUMfcrbi;
return(OK);
case HICUM_MOD_FQI:
value->rValue = model->HICUMfqi;
return(OK);
case HICUM_MOD_RE:
value->rValue = model->HICUMre;
return(OK);
case HICUM_MOD_RCX:
value->rValue = model->HICUMrcx;
return(OK);
case HICUM_MOD_ITSS:
value->rValue = model->HICUMitss;
return(OK);
case HICUM_MOD_MSF:
value->rValue = model->HICUMmsf;
return(OK);
case HICUM_MOD_ISCS:
value->rValue = model->HICUMiscs;
return(OK);
case HICUM_MOD_MSC:
value->rValue = model->HICUMmsc;
return(OK);
case HICUM_MOD_TSF:
value->rValue = model->HICUMtsf;
return(OK);
case HICUM_MOD_RSU:
value->rValue = model->HICUMrsu;
return(OK);
case HICUM_MOD_CSU:
value->rValue = model->HICUMcsu;
return(OK);
case HICUM_MOD_CJEI0:
value->rValue = model->HICUMcjei0;
return(OK);
case HICUM_MOD_VDEI:
value->rValue = model->HICUMvdei;
return(OK);
case HICUM_MOD_ZEI:
value->rValue = model->HICUMzei;
return(OK);
case HICUM_MOD_AJEI:
value->rValue = model->HICUMajei;
return(OK);
case HICUM_MOD_CJEP0:
value->rValue = model->HICUMcjep0;
return(OK);
case HICUM_MOD_VDEP:
value->rValue = model->HICUMvdep;
return(OK);
case HICUM_MOD_ZEP:
value->rValue = model->HICUMzep;
return(OK);
case HICUM_MOD_AJEP:
value->rValue = model->HICUMajep;
return(OK);
case HICUM_MOD_CJCI0:
value->rValue = model->HICUMcjci0;
return(OK);
case HICUM_MOD_VDCI:
value->rValue = model->HICUMvdci;
return(OK);
case HICUM_MOD_ZCI:
value->rValue = model->HICUMzci;
return(OK);
case HICUM_MOD_VPTCI:
value->rValue = model->HICUMvptci;
return(OK);
case HICUM_MOD_CJCX0:
value->rValue = model->HICUMcjcx0;
return(OK);
case HICUM_MOD_VDCX:
value->rValue = model->HICUMvdcx;
return(OK);
case HICUM_MOD_ZCX:
value->rValue = model->HICUMzcx;
return(OK);
case HICUM_MOD_VPTCX:
value->rValue = model->HICUMvptcx;
return(OK);
case HICUM_MOD_FBCPAR:
value->rValue = model->HICUMfbcpar;
return(OK);
case HICUM_MOD_FBEPAR:
value->rValue = model->HICUMfbepar;
return(OK);
case HICUM_MOD_CJS0:
value->rValue = model->HICUMcjs0;
return(OK);
case HICUM_MOD_VDS:
value->rValue = model->HICUMvds;
return(OK);
case HICUM_MOD_ZS:
value->rValue = model->HICUMzs;
return(OK);
case HICUM_MOD_VPTS:
value->rValue = model->HICUMvpts;
return(OK);
case HICUM_MOD_CSCP0:
value->rValue = model->HICUMcscp0;
return(OK);
case HICUM_MOD_VDSP:
value->rValue = model->HICUMvdsp;
return(OK);
case HICUM_MOD_ZSP:
value->rValue = model->HICUMzsp;
return(OK);
case HICUM_MOD_VPTSP:
value->rValue = model->HICUMvptsp;
return(OK);
case HICUM_MOD_T0:
value->rValue = model->HICUMt0;
return(OK);
case HICUM_MOD_DT0H:
value->rValue = model->HICUMdt0h;
return(OK);
case HICUM_MOD_TBVL:
value->rValue = model->HICUMtbvl;
return(OK);
case HICUM_MOD_TEF0:
value->rValue = model->HICUMtef0;
return(OK);
case HICUM_MOD_GTFE:
value->rValue = model->HICUMgtfe;
return(OK);
case HICUM_MOD_THCS:
value->rValue = model->HICUMthcs;
return(OK);
case HICUM_MOD_AHC:
value->rValue = model->HICUMahc;
return(OK);
case HICUM_MOD_FTHC:
value->rValue = model->HICUMfthc;
return(OK);
case HICUM_MOD_RCI0:
value->rValue = model->HICUMrci0;
return(OK);
case HICUM_MOD_VLIM:
value->rValue = model->HICUMvlim;
return(OK);
case HICUM_MOD_VCES:
value->rValue = model->HICUMvces;
return(OK);
case HICUM_MOD_VPT:
value->rValue = model->HICUMvpt;
return(OK);
case HICUM_MOD_AICK:
value->rValue = model->HICUMaick;
return(OK);
case HICUM_MOD_DELCK:
value->rValue = model->HICUMdelck;
return(OK);
case HICUM_MOD_TR:
value->rValue = model->HICUMtr;
return(OK);
case HICUM_MOD_VCBAR:
value->rValue = model->HICUMvcbar;
return(OK);
case HICUM_MOD_ICBAR:
value->rValue = model->HICUMicbar;
return(OK);
case HICUM_MOD_ACBAR:
value->rValue = model->HICUMacbar;
return(OK);
case HICUM_MOD_CBEPAR:
value->rValue = model->HICUMcbepar;
return(OK);
case HICUM_MOD_CBCPAR:
value->rValue = model->HICUMcbcpar;
return(OK);
case HICUM_MOD_ALQF:
value->rValue = model->HICUMalqf;
return(OK);
case HICUM_MOD_ALIT:
value->rValue = model->HICUMalit;
return(OK);
case HICUM_MOD_FLNQS:
value->iValue = model->HICUMflnqs;
return(OK);
case HICUM_MOD_KF:
value->rValue = model->HICUMkf;
return(OK);
case HICUM_MOD_AF:
value->rValue = model->HICUMaf;
return(OK);
case HICUM_MOD_CFBE:
value->rValue = model->HICUMcfbe;
return(OK);
case HICUM_MOD_FLCONO:
value->iValue = model->HICUMflcono;
return(OK);
case HICUM_MOD_KFRE:
value->rValue = model->HICUMkfre;
return(OK);
case HICUM_MOD_AFRE:
value->rValue = model->HICUMafre;
return(OK);
case HICUM_MOD_LATB:
value->rValue = model->HICUMlatb;
return(OK);
case HICUM_MOD_LATL:
value->rValue = model->HICUMlatl;
return(OK);
case HICUM_MOD_VGB:
value->rValue = model->HICUMvgb;
return(OK);
case HICUM_MOD_ALT0:
value->rValue = model->HICUMalt0;
return(OK);
case HICUM_MOD_KT0:
value->rValue = model->HICUMkt0;
return(OK);
case HICUM_MOD_ZETACI:
value->rValue = model->HICUMzetaci;
return(OK);
case HICUM_MOD_ALVS:
value->rValue = model->HICUMalvs;
return(OK);
case HICUM_MOD_ALCES:
value->rValue = model->HICUMalces;
return(OK);
case HICUM_MOD_ZETARBI:
value->rValue = model->HICUMzetarbi;
return(OK);
case HICUM_MOD_ZETARBX:
value->rValue = model->HICUMzetarbx;
return(OK);
case HICUM_MOD_ZETARCX:
value->rValue = model->HICUMzetarcx;
return(OK);
case HICUM_MOD_ZETARE:
value->rValue = model->HICUMzetare;
return(OK);
case HICUM_MOD_ZETACX:
value->rValue = model->HICUMzetacx;
return(OK);
case HICUM_MOD_VGE:
value->rValue = model->HICUMvge;
return(OK);
case HICUM_MOD_VGC:
value->rValue = model->HICUMvgc;
return(OK);
case HICUM_MOD_VGS:
value->rValue = model->HICUMvgs;
return(OK);
case HICUM_MOD_F1VG:
value->rValue = model->HICUMf1vg;
return(OK);
case HICUM_MOD_F2VG:
value->rValue = model->HICUMf2vg;
return(OK);
case HICUM_MOD_ZETACT:
value->rValue = model->HICUMzetact;
return(OK);
case HICUM_MOD_ZETABET:
value->rValue = model->HICUMzetabet;
return(OK);
case HICUM_MOD_ALB:
value->rValue = model->HICUMalb;
return(OK);
case HICUM_MOD_DVGBE:
value->rValue = model->HICUMdvgbe;
return(OK);
case HICUM_MOD_ZETAHJEI:
value->rValue = model->HICUMzetahjei;
return(OK);
case HICUM_MOD_ZETAVGBE:
value->rValue = model->HICUMzetavgbe;
return(OK);
case HICUM_MOD_FLSH:
value->iValue = model->HICUMflsh;
return(OK);
case HICUM_MOD_RTH:
value->rValue = model->HICUMrth;
return(OK);
case HICUM_MOD_ZETARTH:
value->rValue = model->HICUMzetarth;
return(OK);
case HICUM_MOD_ALRTH:
value->rValue = model->HICUMalrth;
return(OK);
case HICUM_MOD_CTH:
value->rValue = model->HICUMcth;
return(OK);
case HICUM_MOD_FLCOMP:
value->rValue = model->HICUMflcomp;
return(OK);
case HICUM_MOD_VBE_MAX:
value->rValue = model->HICUMvbeMax;
return(OK);
case HICUM_MOD_VBC_MAX:
value->rValue = model->HICUMvbcMax;
return(OK);
case HICUM_MOD_VCE_MAX:
value->rValue = model->HICUMvceMax;
return(OK);
default:
return(E_BADPARM);
}
/* NOTREACHED */
}

634
src/spicelib/devices/hicum2/hicum2mpar.c

@ -0,0 +1,634 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine sets model parameters for
* HICUMs in the circuit.
*/
#include "ngspice/ngspice.h"
#include "ngspice/const.h"
#include "ngspice/ifsim.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
HICUMmParam(int param, IFvalue *value, GENmodel *inModel)
{
HICUMmodel *model = (HICUMmodel*)inModel;
switch(param) {
//Circuit simulator specific parameters
case HICUM_MOD_NPN:
if(value->iValue) {
model->HICUMtype = NPN;
}
break;
case HICUM_MOD_PNP:
if(value->iValue) {
model->HICUMtype = PNP;
}
break;
case HICUM_MOD_TNOM:
model->HICUMtnom = value->rValue+CONSTCtoK;
model->HICUMtnomGiven = TRUE;
break;
case HICUM_MOD_VERSION :
model->HICUMversion = value->sValue;
model->HICUMversionGiven = TRUE;
break;
//Transfer current
case HICUM_MOD_C10:
model->HICUMc10 = value->rValue;
model->HICUMc10Given = TRUE;
break;
case HICUM_MOD_QP0:
model->HICUMqp0 = value->rValue;
model->HICUMqp0Given = TRUE;
break;
case HICUM_MOD_ICH:
model->HICUMich = value->rValue;
model->HICUMichGiven = TRUE;
break;
case HICUM_MOD_HF0:
model->HICUMhf0 = value->rValue;
model->HICUMhf0Given = TRUE;
break;
case HICUM_MOD_HFE:
model->HICUMhfe = value->rValue;
model->HICUMhfeGiven = TRUE;
break;
case HICUM_MOD_HFC:
model->HICUMhfc = value->rValue;
model->HICUMhfcGiven = TRUE;
break;
case HICUM_MOD_HJEI:
model->HICUMhjei = value->rValue;
model->HICUMhjeiGiven = TRUE;
break;
case HICUM_MOD_AHJEI:
model->HICUMahjei = value->rValue;
model->HICUMahjeiGiven = TRUE;
break;
case HICUM_MOD_RHJEI:
model->HICUMrhjei = value->rValue;
model->HICUMrhjeiGiven = TRUE;
break;
case HICUM_MOD_HJCI:
model->HICUMhjci = value->rValue;
model->HICUMhjciGiven = TRUE;
break;
//Base-Emitter diode:
case HICUM_MOD_IBEIS:
model->HICUMibeis = value->rValue;
model->HICUMibeisGiven = TRUE;
break;
case HICUM_MOD_MBEI:
model->HICUMmbei = value->rValue;
model->HICUMmbeiGiven = TRUE;
break;
case HICUM_MOD_IREIS:
model->HICUMireis = value->rValue;
model->HICUMireisGiven = TRUE;
break;
case HICUM_MOD_MREI:
model->HICUMmrei = value->rValue;
model->HICUMmreiGiven = TRUE;
break;
case HICUM_MOD_IBEPS:
model->HICUMibeps = value->rValue;
model->HICUMibepsGiven = TRUE;
break;
case HICUM_MOD_MBEP:
model->HICUMmbep = value->rValue;
model->HICUMmbepGiven = TRUE;
break;
case HICUM_MOD_IREPS:
model->HICUMireps = value->rValue;
model->HICUMirepsGiven = TRUE;
break;
case HICUM_MOD_MREP:
model->HICUMmrep = value->rValue;
model->HICUMmrepGiven = TRUE;
break;
case HICUM_MOD_MCF:
model->HICUMmcf = value->rValue;
model->HICUMmcfGiven = TRUE;
break;
//Transit time for excess recombination current at b-c barrier
case HICUM_MOD_TBHREC:
model->HICUMtbhrec = value->rValue;
model->HICUMtbhrecGiven = TRUE;
break;
//Base-Collector diode currents
case HICUM_MOD_IBCIS:
model->HICUMibcis = value->rValue;
model->HICUMibcisGiven = TRUE;
break;
case HICUM_MOD_MBCI:
model->HICUMmbci = value->rValue;
model->HICUMmbciGiven = TRUE;
break;
case HICUM_MOD_IBCXS:
model->HICUMibcxs = value->rValue;
model->HICUMibcxsGiven = TRUE;
break;
case HICUM_MOD_MBCX:
model->HICUMmbcx = value->rValue;
model->HICUMmbcxGiven = TRUE;
break;
//Base-Emitter tunneling current
case HICUM_MOD_IBETS:
model->HICUMibets = value->rValue;
model->HICUMibetsGiven = TRUE;
break;
case HICUM_MOD_ABET:
model->HICUMabet = value->rValue;
model->HICUMabetGiven = TRUE;
break;
case HICUM_MOD_TUNODE:
model->HICUMtunode = value->iValue;
model->HICUMtunodeGiven = TRUE;
break;
//Base-Collector avalanche current
case HICUM_MOD_FAVL:
model->HICUMfavl = value->rValue;
model->HICUMfavlGiven = TRUE;
break;
case HICUM_MOD_QAVL:
model->HICUMqavl = value->rValue;
model->HICUMqavlGiven = TRUE;
break;
case HICUM_MOD_KAVL:
model->HICUMkavl = value->rValue;
model->HICUMkavlGiven = TRUE;
break;
case HICUM_MOD_ALFAV:
model->HICUMalfav = value->rValue;
model->HICUMalfavGiven = TRUE;
break;
case HICUM_MOD_ALQAV:
model->HICUMalqav = value->rValue;
model->HICUMalqavGiven = TRUE;
break;
case HICUM_MOD_ALKAV:
model->HICUMalkav = value->rValue;
model->HICUMalkavGiven = TRUE;
break;
//Series resistances
case HICUM_MOD_RBI0:
model->HICUMrbi0 = value->rValue;
model->HICUMrbi0Given = TRUE;
break;
case HICUM_MOD_RBX:
model->HICUMrbx = value->rValue;
model->HICUMrbxGiven = TRUE;
break;
case HICUM_MOD_FGEO:
model->HICUMfgeo = value->rValue;
model->HICUMfgeoGiven = TRUE;
break;
case HICUM_MOD_FDQR0:
model->HICUMfdqr0 = value->rValue;
model->HICUMfdqr0Given = TRUE;
break;
case HICUM_MOD_FCRBI:
model->HICUMfcrbi = value->rValue;
model->HICUMfcrbiGiven = TRUE;
break;
case HICUM_MOD_FQI:
model->HICUMfqi = value->rValue;
model->HICUMfqiGiven = TRUE;
break;
case HICUM_MOD_RE:
model->HICUMre = value->rValue;
model->HICUMreGiven = TRUE;
break;
case HICUM_MOD_RCX:
model->HICUMrcx = value->rValue;
model->HICUMrcxGiven = TRUE;
break;
//Substrate transistor
case HICUM_MOD_ITSS:
model->HICUMitss = value->rValue;
model->HICUMitssGiven = TRUE;
break;
case HICUM_MOD_MSF:
model->HICUMmsf = value->rValue;
model->HICUMmsfGiven = TRUE;
break;
case HICUM_MOD_ISCS:
model->HICUMiscs = value->rValue;
model->HICUMiscsGiven = TRUE;
break;
case HICUM_MOD_MSC:
model->HICUMmsc = value->rValue;
model->HICUMmscGiven = TRUE;
break;
case HICUM_MOD_TSF:
model->HICUMtsf = value->rValue;
model->HICUMtsfGiven = TRUE;
break;
//Intra-device substrate coupling
case HICUM_MOD_RSU:
model->HICUMrsu = value->rValue;
model->HICUMrsuGiven = TRUE;
break;
case HICUM_MOD_CSU:
model->HICUMcsu = value->rValue;
model->HICUMcsuGiven = TRUE;
break;
//Depletion Capacitances
case HICUM_MOD_CJEI0:
model->HICUMcjei0 = value->rValue;
model->HICUMcjei0Given = TRUE;
break;
case HICUM_MOD_VDEI:
model->HICUMvdei = value->rValue;
model->HICUMvdeiGiven = TRUE;
break;
case HICUM_MOD_ZEI:
model->HICUMzei = value->rValue;
model->HICUMzeiGiven = TRUE;
break;
case HICUM_MOD_AJEI:
model->HICUMajei = value->rValue;
model->HICUMajeiGiven = TRUE;
break;
case HICUM_MOD_CJEP0:
model->HICUMcjep0 = value->rValue;
model->HICUMcjep0Given = TRUE;
break;
case HICUM_MOD_VDEP:
model->HICUMvdep = value->rValue;
model->HICUMvdepGiven = TRUE;
break;
case HICUM_MOD_ZEP:
model->HICUMzep = value->rValue;
model->HICUMzepGiven = TRUE;
break;
case HICUM_MOD_AJEP:
model->HICUMajep = value->rValue;
model->HICUMajepGiven = TRUE;
break;
case HICUM_MOD_CJCI0:
model->HICUMcjci0 = value->rValue;
model->HICUMcjci0Given = TRUE;
break;
case HICUM_MOD_VDCI:
model->HICUMvdci = value->rValue;
model->HICUMvdciGiven = TRUE;
break;
case HICUM_MOD_ZCI:
model->HICUMzci = value->rValue;
model->HICUMzciGiven = TRUE;
break;
case HICUM_MOD_VPTCI:
model->HICUMvptci = value->rValue;
model->HICUMvptciGiven = TRUE;
break;
case HICUM_MOD_CJCX0:
model->HICUMcjcx0 = value->rValue;
model->HICUMcjcx0Given = TRUE;
break;
case HICUM_MOD_VDCX:
model->HICUMvdcx = value->rValue;
model->HICUMvdcxGiven = TRUE;
break;
case HICUM_MOD_ZCX:
model->HICUMzcx = value->rValue;
model->HICUMzcxGiven = TRUE;
break;
case HICUM_MOD_VPTCX:
model->HICUMvptcx = value->rValue;
model->HICUMvptcxGiven = TRUE;
break;
case HICUM_MOD_FBCPAR:
model->HICUMfbcpar = value->rValue;
model->HICUMfbcparGiven = TRUE;
break;
case HICUM_MOD_FBEPAR:
model->HICUMfbepar = value->rValue;
model->HICUMfbeparGiven = TRUE;
break;
case HICUM_MOD_CJS0:
model->HICUMcjs0 = value->rValue;
model->HICUMcjs0Given = TRUE;
break;
case HICUM_MOD_VDS:
model->HICUMvds = value->rValue;
model->HICUMvdsGiven = TRUE;
break;
case HICUM_MOD_ZS:
model->HICUMzs = value->rValue;
model->HICUMzsGiven = TRUE;
break;
case HICUM_MOD_VPTS:
model->HICUMvpts = value->rValue;
model->HICUMvptsGiven = TRUE;
break;
case HICUM_MOD_CSCP0:
model->HICUMcscp0 = value->rValue;
model->HICUMcscp0Given = TRUE;
break;
case HICUM_MOD_VDSP:
model->HICUMvdsp = value->rValue;
model->HICUMvdspGiven = TRUE;
break;
case HICUM_MOD_ZSP:
model->HICUMzsp = value->rValue;
model->HICUMzspGiven = TRUE;
break;
case HICUM_MOD_VPTSP:
model->HICUMvptsp = value->rValue;
model->HICUMvptspGiven = TRUE;
break;
//Diffusion Capacitances
case HICUM_MOD_T0:
model->HICUMt0 = value->rValue;
model->HICUMt0Given = TRUE;
break;
case HICUM_MOD_DT0H:
model->HICUMdt0h = value->rValue;
model->HICUMdt0hGiven = TRUE;
break;
case HICUM_MOD_TBVL:
model->HICUMtbvl = value->rValue;
model->HICUMtbvlGiven = TRUE;
break;
case HICUM_MOD_TEF0:
model->HICUMtef0 = value->rValue;
model->HICUMtef0Given = TRUE;
break;
case HICUM_MOD_GTFE:
model->HICUMgtfe = value->rValue;
model->HICUMgtfeGiven = TRUE;
break;
case HICUM_MOD_THCS:
model->HICUMthcs = value->rValue;
model->HICUMthcsGiven = TRUE;
break;
case HICUM_MOD_AHC:
model->HICUMahc = value->rValue;
model->HICUMahcGiven = TRUE;
break;
case HICUM_MOD_FTHC:
model->HICUMfthc = value->rValue;
model->HICUMfthcGiven = TRUE;
break;
case HICUM_MOD_RCI0:
model->HICUMrci0 = value->rValue;
model->HICUMrci0Given = TRUE;
break;
case HICUM_MOD_VLIM:
model->HICUMvlim = value->rValue;
model->HICUMvlimGiven = TRUE;
break;
case HICUM_MOD_VCES:
model->HICUMvces = value->rValue;
model->HICUMvcesGiven = TRUE;
break;
case HICUM_MOD_VPT:
model->HICUMvpt = value->rValue;
model->HICUMvptGiven = TRUE;
break;
case HICUM_MOD_AICK:
model->HICUMaick = value->rValue;
model->HICUMaickGiven = TRUE;
break;
case HICUM_MOD_DELCK:
model->HICUMdelck = value->rValue;
model->HICUMdelckGiven = TRUE;
break;
case HICUM_MOD_TR:
model->HICUMtr = value->rValue;
model->HICUMtrGiven = TRUE;
break;
case HICUM_MOD_VCBAR:
model->HICUMvcbar = value->rValue;
model->HICUMvcbarGiven = TRUE;
break;
case HICUM_MOD_ICBAR:
model->HICUMicbar = value->rValue;
model->HICUMicbarGiven = TRUE;
break;
case HICUM_MOD_ACBAR:
model->HICUMacbar = value->rValue;
model->HICUMacbarGiven = TRUE;
break;
//Isolation Capacitances
case HICUM_MOD_CBEPAR:
model->HICUMcbepar = value->rValue;
model->HICUMcbeparGiven = TRUE;
break;
case HICUM_MOD_CBCPAR:
model->HICUMcbcpar = value->rValue;
model->HICUMcbcparGiven = TRUE;
break;
//Non-quasi-static Effect
case HICUM_MOD_ALQF:
model->HICUMalqf = value->rValue;
model->HICUMalqfGiven = TRUE;
break;
case HICUM_MOD_ALIT:
model->HICUMalit = value->rValue;
model->HICUMalitGiven = TRUE;
break;
case HICUM_MOD_FLNQS:
model->HICUMflnqs = value->iValue;
model->HICUMflnqsGiven = TRUE;
break;
//Noise
case HICUM_MOD_KF:
model->HICUMkf = value->rValue;
model->HICUMkfGiven = TRUE;
break;
case HICUM_MOD_AF:
model->HICUMaf = value->rValue;
model->HICUMafGiven = TRUE;
break;
case HICUM_MOD_CFBE:
model->HICUMcfbe = value->iValue;
model->HICUMcfbeGiven = TRUE;
break;
case HICUM_MOD_FLCONO:
model->HICUMflcono = value->iValue;
model->HICUMflconoGiven = TRUE;
break;
case HICUM_MOD_KFRE:
model->HICUMkfre = value->rValue;
model->HICUMkfreGiven = TRUE;
break;
case HICUM_MOD_AFRE:
model->HICUMafre = value->rValue;
model->HICUMafreGiven = TRUE;
break;
//Lateral Geometry Scaling (at high current densities)
case HICUM_MOD_LATB:
model->HICUMlatb = value->rValue;
model->HICUMlatbGiven = TRUE;
break;
case HICUM_MOD_LATL:
model->HICUMlatl = value->rValue;
model->HICUMlatlGiven = TRUE;
break;
//Temperature dependence
case HICUM_MOD_VGB:
model->HICUMvgb = value->rValue;
model->HICUMvgbGiven = TRUE;
break;
case HICUM_MOD_ALT0:
model->HICUMalt0 = value->rValue;
model->HICUMalt0Given = TRUE;
break;
case HICUM_MOD_KT0:
model->HICUMkt0 = value->rValue;
model->HICUMkt0Given = TRUE;
break;
case HICUM_MOD_ZETACI:
model->HICUMzetaci = value->rValue;
model->HICUMzetaciGiven = TRUE;
break;
case HICUM_MOD_ALVS:
model->HICUMalvs = value->rValue;
model->HICUMalvsGiven = TRUE;
break;
case HICUM_MOD_ALCES:
model->HICUMalces = value->rValue;
model->HICUMalcesGiven = TRUE;
break;
case HICUM_MOD_ZETARBI:
model->HICUMzetarbi = value->rValue;
model->HICUMzetarbiGiven = TRUE;
break;
case HICUM_MOD_ZETARBX:
model->HICUMzetarbx = value->rValue;
model->HICUMzetarbxGiven = TRUE;
break;
case HICUM_MOD_ZETARCX:
model->HICUMzetarcx = value->rValue;
model->HICUMzetarcxGiven = TRUE;
break;
case HICUM_MOD_ZETARE:
model->HICUMzetare = value->rValue;
model->HICUMzetareGiven = TRUE;
break;
case HICUM_MOD_ZETACX:
model->HICUMzetacx = value->rValue;
model->HICUMzetacxGiven = TRUE;
break;
case HICUM_MOD_VGE:
model->HICUMvge = value->rValue;
model->HICUMvgeGiven = TRUE;
break;
case HICUM_MOD_VGC:
model->HICUMvgc = value->rValue;
model->HICUMvgcGiven = TRUE;
break;
case HICUM_MOD_VGS:
model->HICUMvgs = value->rValue;
model->HICUMvgsGiven = TRUE;
break;
case HICUM_MOD_F1VG:
model->HICUMf1vg = value->rValue;
model->HICUMf1vgGiven = TRUE;
break;
case HICUM_MOD_F2VG:
model->HICUMf2vg = value->rValue;
model->HICUMf2vgGiven = TRUE;
break;
case HICUM_MOD_ZETACT:
model->HICUMzetact = value->rValue;
model->HICUMzetactGiven = TRUE;
break;
case HICUM_MOD_ZETABET:
model->HICUMzetabet = value->rValue;
model->HICUMzetabetGiven = TRUE;
break;
case HICUM_MOD_ALB:
model->HICUMalb = value->rValue;
model->HICUMalbGiven = TRUE;
break;
case HICUM_MOD_DVGBE:
model->HICUMdvgbe = value->rValue;
model->HICUMdvgbeGiven = TRUE;
break;
case HICUM_MOD_ZETAHJEI:
model->HICUMzetahjei = value->rValue;
model->HICUMzetahjeiGiven = TRUE;
break;
case HICUM_MOD_ZETAVGBE:
model->HICUMzetavgbe = value->rValue;
model->HICUMzetavgbeGiven = TRUE;
break;
//Self-Heating
case HICUM_MOD_FLSH:
model->HICUMflsh = value->iValue;
model->HICUMflshGiven = TRUE;
break;
case HICUM_MOD_RTH:
model->HICUMrth = value->rValue;
model->HICUMrthGiven = TRUE;
break;
case HICUM_MOD_ZETARTH:
model->HICUMzetarth = value->rValue;
model->HICUMzetarthGiven = TRUE;
break;
case HICUM_MOD_ALRTH:
model->HICUMalrth = value->rValue;
model->HICUMalrthGiven = TRUE;
break;
case HICUM_MOD_CTH:
model->HICUMcth = value->rValue;
model->HICUMcthGiven = TRUE;
break;
//Compatibility with V2.1
case HICUM_MOD_FLCOMP:
model->HICUMflcomp = value->rValue;
model->HICUMflcompGiven = TRUE;
break;
//SOA-check
case HICUM_MOD_VBE_MAX:
model->HICUMvbeMax = value->rValue;
model->HICUMvbeMaxGiven = TRUE;
break;
case HICUM_MOD_VBC_MAX:
model->HICUMvbcMax = value->rValue;
model->HICUMvbcMaxGiven = TRUE;
break;
case HICUM_MOD_VCE_MAX:
model->HICUMvceMax = value->rValue;
model->HICUMvceMaxGiven = TRUE;
break;
default:
return(E_BADPARM);
}
return(OK);
}

293
src/spicelib/devices/hicum2/hicum2noise.c

@ -0,0 +1,293 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#include "ngspice/ngspice.h"
#include "hicum2defs.h"
#include "ngspice/cktdefs.h"
#include "ngspice/iferrmsg.h"
#include "ngspice/noisedef.h"
#include "ngspice/suffix.h"
/*
* HICUMnoise (mode, operation, firstModel, ckt, data, OnDens)
*
* This routine names and evaluates all of the noise sources
* associated with HICUM's. It starts with the model *firstModel and
* traverses all of its insts. It then proceeds to any other models
* on the linked list. The total output noise density generated by
* all of the HICUM's is summed with the variable "OnDens".
*/
int
HICUMnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, Ndata *data, double *OnDens)
{
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
HICUMmodel *firstModel = (HICUMmodel *) genmodel;
HICUMmodel *model;
HICUMinstance *here;
double tempOnoise;
double tempInoise;
double noizDens[HICUMNSRCS];
double lnNdens[HICUMNSRCS];
int i;
double Ibbp_Vbbp;
double Icic_Vcic;
double Ibpbi_Vbpbi;
double Ieie_Veie;
double Isis_Vsis;
/* define the names of the noise sources */
static char *HICUMnNames[HICUMNSRCS] = {
/* Note that we have to keep the order consistent with the
strchr definitions in HICUMdefs.h */
"_rcx", /* thermal noise due to rcx */
"_rbx", /* thermal noise due to rbx */
"_rbi", /* thermal noise due to rbi */
"_re", /* thermal noise due to re */
"_rsu", /* thermal noise due to rsu */
"_iavl", /* shot noise due to iavl */
"_ibci", /* shot noise due to ibci */
"_ibep", /* shot noise due to ibep */
"_ijbcx", /* shot noise due to ijbcx */
"_ijsc", /* shot noise due to ijsc */
"_it", /* shot noise due to iciei */
"_ibei", /* shot noise due to ibiei */
"_1overfbe", /* flicker (1/f) noise ibe */
"_1overfre", /* flicker (1/f) noise re */
"" /* total transistor noise */
};
for (model=firstModel; model != NULL; model=HICUMnextModel(model)) {
for (here=HICUMinstances(model); here != NULL;
here=HICUMnextInstance(here)) {
// get all derivatives of branch DC currents
if(model->HICUMrcxGiven && model->HICUMrcx != 0) {
Icic_Vcic = 1/here->HICUMrcx_t.rpart;
} else {
Icic_Vcic = 0.0;
}
if(model->HICUMrbxGiven && model->HICUMrbx != 0) {
Ibbp_Vbbp = 1/here->HICUMrbx_t.rpart;
} else {
Ibbp_Vbbp = 0.0;
}
if(model->HICUMreGiven && model->HICUMre != 0) {
Ieie_Veie = 1/here->HICUMre_t.rpart;
} else {
Ieie_Veie = 0.0;
}
if(model->HICUMrsuGiven && model->HICUMrsu != 0) {
Isis_Vsis = 1/model->HICUMrsu*here->HICUMm;
} else {
Isis_Vsis = 0.0;
}
if(here->HICUMrbi > 0) {
Ibpbi_Vbpbi = 1/here->HICUMrbi;
} else {
Ibpbi_Vbpbi = 0.0;
}
switch (operation) {
case N_OPEN:
/* see if we have to to produce a summary report */
/* if so, name all the noise generators */
if (job->NStpsSm != 0) {
switch (mode) {
case N_DENS:
for (i=0; i < HICUMNSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_%s%s", here->HICUMname, HICUMnNames[i]);
}
break;
case INT_NOIZ:
for (i=0; i < HICUMNSRCS; i++) {
NOISE_ADD_OUTVAR(ckt, data, "onoise_total_%s%s", here->HICUMname, HICUMnNames[i]);
NOISE_ADD_OUTVAR(ckt, data, "inoise_total_%s%s", here->HICUMname, HICUMnNames[i]);
}
break;
}
}
break;
case N_CALC:
switch (mode) {
case N_DENS:
NevalSrc(&noizDens[HICUMRCNOIZ],&lnNdens[HICUMRCNOIZ],
ckt,THERMNOISE,here->HICUMcollCINode,here->HICUMcollNode,
Icic_Vcic);
NevalSrc(&noizDens[HICUMRBNOIZ],&lnNdens[HICUMRBNOIZ],
ckt,THERMNOISE,here->HICUMbaseNode,here->HICUMbaseBPNode,
Ibbp_Vbbp);
NevalSrc(&noizDens[HICUMRBINOIZ],&lnNdens[HICUMRBINOIZ],
ckt,THERMNOISE,here->HICUMbaseBPNode,here->HICUMbaseBINode,
Ibpbi_Vbpbi);
NevalSrc(&noizDens[HICUMRENOIZ],&lnNdens[HICUMRENOIZ],
ckt,THERMNOISE,here->HICUMemitEINode,here->HICUMemitNode,
Ieie_Veie);
NevalSrc(&noizDens[HICUMRSNOIZ],&lnNdens[HICUMRSNOIZ],
ckt,THERMNOISE,here->HICUMsubsSINode,here->HICUMsubsNode,
Isis_Vsis);
NevalSrc(&noizDens[HICUMIAVLNOIZ],&lnNdens[HICUMIAVLNOIZ],
ckt,SHOTNOISE,here->HICUMcollCINode,here->HICUMbaseBINode,
here->HICUMiavl);
NevalSrc(&noizDens[HICUMIBCINOIZ],&lnNdens[HICUMIBCINOIZ],
ckt,SHOTNOISE,here->HICUMbaseBINode,here->HICUMcollCINode,
*(ckt->CKTstate0 + here->HICUMibici)+here->HICUMiavl);
NevalSrc(&noizDens[HICUMIBEPNOIZ],&lnNdens[HICUMIBEPNOIZ],
ckt,SHOTNOISE,here->HICUMbaseBPNode,here->HICUMemitEINode,
*(ckt->CKTstate0 + here->HICUMibpei));
NevalSrc(&noizDens[HICUMIBCXNOIZ],&lnNdens[HICUMIBCXNOIZ],
ckt,SHOTNOISE,here->HICUMbaseBPNode,here->HICUMcollCINode,
*(ckt->CKTstate0 + here->HICUMibpci));
NevalSrc(&noizDens[HICUMIJSCNOIZ],&lnNdens[HICUMIJSCNOIZ],
ckt,SHOTNOISE,here->HICUMsubsSINode,here->HICUMcollCINode,
*(ckt->CKTstate0 + here->HICUMisici));
NevalSrc(&noizDens[HICUMITNOIZ],&lnNdens[HICUMITNOIZ],
ckt,SHOTNOISE,here->HICUMcollCINode,here->HICUMemitEINode,
*(ckt->CKTstate0 + here->HICUMit));
NevalSrc(&noizDens[HICUMIBEINOIZ],&lnNdens[HICUMIBEINOIZ],
ckt,SHOTNOISE,here->HICUMbaseBINode,here->HICUMemitEINode,
*(ckt->CKTstate0 + here->HICUMibiei));
if (model->HICUMcfbe == -1) {
NevalSrc(&noizDens[HICUMFLBENOIZ], NULL, ckt,
N_GAIN,here->HICUMbaseBINode, here->HICUMemitEINode,
(double)0.0);
} else {
NevalSrc(&noizDens[HICUMFLBENOIZ], NULL, ckt,
N_GAIN,here->HICUMbaseBPNode, here->HICUMemitEINode,
(double)0.0);
}
noizDens[HICUMFLBENOIZ] *= here->HICUMkf_scaled *
exp(model->HICUMaf *
log(MAX(fabs((*(ckt->CKTstate0 + here->HICUMibiei)+*(ckt->CKTstate0 + here->HICUMibpei))),N_MINLOG))) /
data->freq;
lnNdens[HICUMFLBENOIZ] =
log(MAX(noizDens[HICUMFLBENOIZ],N_MINLOG));
NevalSrc(&noizDens[HICUMFLRENOIZ], NULL, ckt,
N_GAIN,here->HICUMemitEINode, here->HICUMemitNode,
(double)0.0);
noizDens[HICUMFLRENOIZ] *= here->HICUMkfre_scaled *
exp(model->HICUMafre *
log(MAX(fabs(*(ckt->CKTstate0 + here->HICUMieie)),N_MINLOG))) /
data->freq;
lnNdens[HICUMFLRENOIZ] =
log(MAX(noizDens[HICUMFLRENOIZ],N_MINLOG));
noizDens[HICUMTOTNOIZ] = noizDens[HICUMRCNOIZ] +
noizDens[HICUMRBNOIZ] +
noizDens[HICUMRBINOIZ] +
noizDens[HICUMRENOIZ] +
noizDens[HICUMRSNOIZ] +
noizDens[HICUMIAVLNOIZ] +
noizDens[HICUMIBCINOIZ] +
noizDens[HICUMIBEPNOIZ] +
noizDens[HICUMIBCXNOIZ] +
noizDens[HICUMIJSCNOIZ] +
noizDens[HICUMITNOIZ] +
noizDens[HICUMIBEINOIZ] +
noizDens[HICUMFLBENOIZ] +
noizDens[HICUMFLRENOIZ];
lnNdens[HICUMTOTNOIZ] =
log(noizDens[HICUMTOTNOIZ]);
*OnDens += noizDens[HICUMTOTNOIZ];
if (data->delFreq == 0.0) {
/* if we haven't done any previous integration, we need to */
/* initialize our "history" variables */
for (i=0; i < HICUMNSRCS; i++) {
here->HICUMnVar[LNLSTDENS][i] = lnNdens[i];
}
/* clear out our integration variables if it's the first pass */
if (data->freq == job->NstartFreq) {
for (i=0; i < HICUMNSRCS; i++) {
here->HICUMnVar[OUTNOIZ][i] = 0.0;
here->HICUMnVar[INNOIZ][i] = 0.0;
}
}
} else { /* data->delFreq != 0.0 (we have to integrate) */
/* In order to get the best curve fit, we have to integrate each component separately */
for (i=0; i < HICUMNSRCS; i++) {
if (i != HICUMTOTNOIZ) {
tempOnoise = Nintegrate(noizDens[i], lnNdens[i],
here->HICUMnVar[LNLSTDENS][i], data);
tempInoise = Nintegrate(noizDens[i] * data->GainSqInv ,
lnNdens[i] + data->lnGainInv,
here->HICUMnVar[LNLSTDENS][i] + data->lnGainInv,
data);
here->HICUMnVar[LNLSTDENS][i] = lnNdens[i];
data->outNoiz += tempOnoise;
data->inNoise += tempInoise;
if (job->NStpsSm != 0) {
here->HICUMnVar[OUTNOIZ][i] += tempOnoise;
here->HICUMnVar[OUTNOIZ][HICUMTOTNOIZ] += tempOnoise;
here->HICUMnVar[INNOIZ][i] += tempInoise;
here->HICUMnVar[INNOIZ][HICUMTOTNOIZ] += tempInoise;
}
}
}
}
if (data->prtSummary) {
for (i=0; i < HICUMNSRCS; i++) { /* print a summary report */
data->outpVector[data->outNumber++] = noizDens[i];
}
}
break;
case INT_NOIZ: /* already calculated, just output */
if (job->NStpsSm != 0) {
for (i=0; i < HICUMNSRCS; i++) {
data->outpVector[data->outNumber++] = here->HICUMnVar[OUTNOIZ][i];
data->outpVector[data->outNumber++] = here->HICUMnVar[INNOIZ][i];
}
} /* if */
break;
} /* switch (mode) */
break;
case N_CLOSE:
return (OK); /* do nothing, the main calling routine will close */
break; /* the plots */
} /* switch (operation) */
} /* for here */
} /* for model */
return(OK);
}

70
src/spicelib/devices/hicum2/hicum2param.c

@ -0,0 +1,70 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine sets instance parameters for
* HICUMs in the circuit.
*/
#include "ngspice/ngspice.h"
#include "ngspice/const.h"
#include "ngspice/ifsim.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
/* ARGSUSED */
int
HICUMparam(int param, IFvalue *value, GENinstance *instPtr, IFvalue *select)
{
HICUMinstance *here = (HICUMinstance*)instPtr;
NG_IGNORE(select);
switch(param) {
case HICUM_AREA:
here->HICUMarea = value->rValue;
here->HICUMareaGiven = TRUE;
break;
case HICUM_OFF:
here->HICUMoff = (value->iValue != 0);
break;
case HICUM_TEMP:
here->HICUMtemp = value->rValue+CONSTCtoK;
here->HICUMtempGiven = TRUE;
break;
case HICUM_DTEMP:
here->HICUMdtemp = value->rValue;
here->HICUMdtempGiven = TRUE;
break;
case HICUM_M:
here->HICUMm = value->rValue;
here->HICUMmGiven = TRUE;
break;
case HICUM_IC :
switch(value->v.numValue) {
case 3:
here->HICUMicVCS = *(value->v.vec.rVec+2);
here->HICUMicVCSGiven = TRUE;
/* fallthrough */
case 2:
here->HICUMicVCE = *(value->v.vec.rVec+1);
here->HICUMicVCEGiven = TRUE;
/* fallthrough */
case 1:
here->HICUMicVBE = *(value->v.vec.rVec);
here->HICUMicVBEGiven = TRUE;
break;
default:
return(E_BADPARM);
}
break;
default:
return(E_BADPARM);
}
return(OK);
}

758
src/spicelib/devices/hicum2/hicum2pzld.c

@ -0,0 +1,758 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* Function to load the COMPLEX circuit matrix using the
* small signal parameters saved during a previous DC operating
* point analysis.
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
HICUMpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
{
HICUMinstance *here;
HICUMmodel *model = (HICUMmodel*)inModel;
double Ibpei_Vbpei;
double Ibpei_Vrth;
double Ibiei_Vbiei;
double Ibiei_Vxf;
double Ibiei_Vbici;
double Ibiei_Vrth;
double Ibici_Vbici;
double Ibici_Vbiei;
double Ibici_Vrth;
double Ibpci_Vbpci;
double Ibpci_Vrth;
double Isici_Vsici;
double Isici_Vrth;
double Iciei_Vbiei;
double Iciei_Vbici;
double Iciei_Vrth;
double Iciei_Vxf2;
double Ibpbi_Vbpbi;
double Ibpbi_Vbici;
double Ibpbi_Vbiei;
double Ibpbi_Vrth;
double Isis_Vsis;
double Icic_Vcic, Icic_Vrth;
double Ieie_Veie, Ieie_Vrth;
double Ibbp_Vbbp, Ibbp_Vrth;
double Irth_Vrth;
double Ibpsi_Vbpci;
double Ibpsi_Vsici;
double Ibpsi_Vrth;
double XQrbi_Vbpbi;
double XQrbi_Vbiei;
double XQrbi_Vbici;
double XQrbi_Vrth;
double XQjei_Vbiei;
double XQjei_Vrth;
double XQjci_Vbici;
double XQjci_Vrth;
double XQjep_Vbpei;
double XQjep_Vrth;
double volatile Xqjcx0_t_i_Vbci;
double Xqjcx0_t_i_Vrth;
double volatile Xqjcx0_t_ii_Vbpci;
double Xqjcx0_t_ii_Vrth;
double XQdsu_Vbpci;
double XQdsu_Vsici;
double XQdsu_Vrth;
double XQjs_Vsici;
double XQjs_Vrth;
double XQscp_Vsc;
double XQscp_Vrth;
double XQbepar1_Vbe;
double XQbepar2_Vbpe;
double XQbcpar1_Vbci;
double XQbcpar2_Vbpci;
double XQsu_Vsis;
double XQcth_Vrth;
double XQf_Vbiei;
double XQf_Vbici;
double XQf_Vrth;
double XQf_Vxf;
double XQr_Vrth;
double XQr_Vbiei;
double XQr_Vbici;
double XQxf_Vxf;
double XQxf1_Vxf1;
double XQxf2_Vxf2;
double Ixf1_Vbiei;
double Ixf1_Vbici;
double Ixf1_Vxf2 ;
double Ixf1_Vxf1 ;
double Ixf1_Vrth ;
double Ixf2_Vbiei;
double Ixf2_Vbici;
double Ixf2_Vxf2 ;
double Ixf2_Vxf1 ;
double Ixf2_Vrth ;
double Ixf_Vbiei ;
double Ixf_Vbici ;
double Ixf_Vxf ;
double Ixf_Vrth ;
double Ith_Vrth, Ith_Vbiei, Ith_Vbici, Ith_Vbpbi, Ith_Vbpci, Ith_Vbpei, Ith_Vciei, Ith_Vsici, Ith_Vcic, Ith_Vbbp, Ith_Veie;
/* loop through all the models */
for( ; model != NULL; model = HICUMnextModel(model)) {
int selfheat = ( (model->HICUMflsh > 0) && (model->HICUMrthGiven) && (model->HICUMrth > 0.0));
int nqs = ( (model->HICUMflnqs != 0 || model->HICUMflcomp < 2.3) && (model->HICUMalit > 0 || model->HICUMalqf > 0));
/* loop through all the instances of the model */
for( here = HICUMinstances(model); here!= NULL;
here = HICUMnextInstance(here)) {
// get all derivatives of branch DC currents
if(model->HICUMrcxGiven && model->HICUMrcx != 0) {
Icic_Vcic = 1/here->HICUMrcx_t.rpart;
Icic_Vrth = -*(ckt->CKTstate0 + here->HICUMvcic)/here->HICUMrcx_t.rpart/here->HICUMrcx_t.rpart*here->HICUMrcx_t.dpart;
} else {
Icic_Vcic = 0.0;
Icic_Vrth = 0.0;
}
if(model->HICUMrbxGiven && model->HICUMrbx != 0) {
Ibbp_Vbbp = 1/here->HICUMrbx_t.rpart;
Ibbp_Vrth = -*(ckt->CKTstate0 + here->HICUMvbbp)/here->HICUMrbx_t.rpart/here->HICUMrbx_t.rpart*here->HICUMrbx_t.dpart;
} else {
Ibbp_Vbbp = 0.0;
Ibbp_Vrth = 0.0;
}
if(model->HICUMreGiven && model->HICUMre != 0) {
Ieie_Veie = 1/here->HICUMre_t.rpart;
Ieie_Vrth = -*(ckt->CKTstate0 + here->HICUMveie)/here->HICUMre_t.rpart/here->HICUMre_t.rpart*here->HICUMre_t.dpart;
} else {
Ieie_Veie = 0.0;
Ieie_Vrth = 0.0;
}
if(model->HICUMrsuGiven && model->HICUMrsu != 0) {
Isis_Vsis = 1/model->HICUMrsu*here->HICUMm;
} else {
Isis_Vsis = 0.0;
}
if(selfheat) {
Irth_Vrth = (1/here->HICUMrth_t.rpart - *(ckt->CKTstate0 + here->HICUMvrth)/(here->HICUMrth_t.rpart*here->HICUMrth_t.rpart) * here->HICUMrth_t.dpart);
} else {
Irth_Vrth = 0.0;
}
Ibiei_Vbiei = *(ckt->CKTstate0 + here->HICUMibiei_Vbiei);
Ibiei_Vxf = *(ckt->CKTstate0 + here->HICUMibiei_Vxf);
Ibiei_Vbici = *(ckt->CKTstate0 + here->HICUMibiei_Vbici);
Ibiei_Vrth = *(ckt->CKTstate0 + here->HICUMibiei_Vrth);
Ibpei_Vbpei = *(ckt->CKTstate0 + here->HICUMibpei_Vbpei);
Ibpei_Vrth = *(ckt->CKTstate0 + here->HICUMibpei_Vrth);
Iciei_Vbiei = *(ckt->CKTstate0 + here->HICUMiciei_Vbiei);
Iciei_Vbici = *(ckt->CKTstate0 + here->HICUMiciei_Vbici);
Iciei_Vrth = *(ckt->CKTstate0 + here->HICUMiciei_Vrth);
Iciei_Vxf2 = *(ckt->CKTstate0 + here->HICUMiciei_Vxf2);
Ibici_Vbici = *(ckt->CKTstate0 + here->HICUMibici_Vbici);
Ibici_Vbiei = *(ckt->CKTstate0 + here->HICUMibici_Vbiei);
Ibici_Vrth = *(ckt->CKTstate0 + here->HICUMibici_Vrth);
Ibpbi_Vbpbi = *(ckt->CKTstate0 + here->HICUMibpbi_Vbpbi);
Ibpbi_Vbiei = *(ckt->CKTstate0 + here->HICUMibpbi_Vbiei);
Ibpbi_Vbici = *(ckt->CKTstate0 + here->HICUMibpbi_Vbici);
Ibpbi_Vrth = *(ckt->CKTstate0 + here->HICUMibpbi_Vrth);
Ibpci_Vbpci = *(ckt->CKTstate0 + here->HICUMibpci_Vbpci);
Ibpci_Vrth = *(ckt->CKTstate0 + here->HICUMibpci_Vrth);
Isici_Vsici = *(ckt->CKTstate0 + here->HICUMisici_Vsici);
Isici_Vrth = *(ckt->CKTstate0 + here->HICUMisici_Vrth);
Ibpsi_Vbpci = *(ckt->CKTstate0 + here->HICUMibpsi_Vbpci);
Ibpsi_Vsici = *(ckt->CKTstate0 + here->HICUMibpsi_Vsici);
Ibpsi_Vrth = *(ckt->CKTstate0 + here->HICUMibpsi_Vrth);
Ith_Vrth = *(ckt->CKTstate0 + here->HICUMith_Vrth);
Ith_Vbiei = *(ckt->CKTstate0 + here->HICUMith_Vbiei);
Ith_Vbici = *(ckt->CKTstate0 + here->HICUMith_Vbici);
Ith_Vbpbi = *(ckt->CKTstate0 + here->HICUMith_Vbpbi);
Ith_Vbpci = *(ckt->CKTstate0 + here->HICUMith_Vbpci);
Ith_Vbpei = *(ckt->CKTstate0 + here->HICUMith_Vbpei);
Ith_Vciei = *(ckt->CKTstate0 + here->HICUMith_Vciei);
Ith_Vsici = *(ckt->CKTstate0 + here->HICUMith_Vsici);
Ith_Vcic = *(ckt->CKTstate0 + here->HICUMith_Vcic);
Ith_Vbbp = *(ckt->CKTstate0 + here->HICUMith_Vbbp);
Ith_Veie = *(ckt->CKTstate0 + here->HICUMith_Veie);
Ixf1_Vbiei = *(ckt->CKTstate0 + here->HICUMixf1_Vbiei);
Ixf1_Vbici = *(ckt->CKTstate0 + here->HICUMixf1_Vbici);
Ixf1_Vxf2 = *(ckt->CKTstate0 + here->HICUMixf1_Vxf2);
Ixf1_Vxf1 = *(ckt->CKTstate0 + here->HICUMixf1_Vxf1);
Ixf1_Vrth = *(ckt->CKTstate0 + here->HICUMixf1_Vrth);
Ixf2_Vbiei = *(ckt->CKTstate0 + here->HICUMixf2_Vbiei);
Ixf2_Vbici = *(ckt->CKTstate0 + here->HICUMixf2_Vbici);
Ixf2_Vxf2 = *(ckt->CKTstate0 + here->HICUMixf2_Vxf2);
Ixf2_Vxf1 = *(ckt->CKTstate0 + here->HICUMixf2_Vxf1);
Ixf2_Vrth = *(ckt->CKTstate0 + here->HICUMixf2_Vrth);
Ixf_Vbiei = *(ckt->CKTstate0 + here->HICUMixf_Vbiei);
Ixf_Vbici = *(ckt->CKTstate0 + here->HICUMixf_Vbici);
Ixf_Vxf = *(ckt->CKTstate0 + here->HICUMixf_Vxf);
Ixf_Vrth = *(ckt->CKTstate0 + here->HICUMixf_Vrth);
////////////////////////////////////
////////// The real part /////////
////////////////////////////////////
// Stamp element: Ibiei
*(here->HICUMbaseBIBaseBIPtr) += Ibiei_Vbiei;
*(here->HICUMemitEIEmitEIPtr) += Ibiei_Vbiei;
*(here->HICUMbaseBIEmitEIPtr) += -Ibiei_Vbiei;
*(here->HICUMemitEIBaseBIPtr) += -Ibiei_Vbiei;
*(here->HICUMbaseBIBaseBIPtr) += Ibiei_Vbici;
*(here->HICUMemitEICollCIPtr) += Ibiei_Vbici;
*(here->HICUMbaseBICollCIPtr) += -Ibiei_Vbici;
*(here->HICUMemitEIBaseBIPtr) += -Ibiei_Vbici;
// Stamp element: Ibpei
*(here->HICUMbaseBPBaseBPPtr) += Ibpei_Vbpei;
*(here->HICUMemitEIEmitEIPtr) += Ibpei_Vbpei;
*(here->HICUMbaseBPEmitEIPtr) += -Ibpei_Vbpei;
*(here->HICUMemitEIBaseBPPtr) += -Ibpei_Vbpei;;
// Stamp element: Ibici
*(here->HICUMbaseBIBaseBIPtr) += Ibici_Vbici;
*(here->HICUMcollCICollCIPtr) += Ibici_Vbici;
*(here->HICUMcollCIBaseBIPtr) += -Ibici_Vbici;
*(here->HICUMbaseBICollCIPtr) += -Ibici_Vbici;
*(here->HICUMbaseBIBaseBIPtr) += Ibici_Vbiei;
*(here->HICUMcollCIEmitEIPtr) += Ibici_Vbiei;
*(here->HICUMcollCIBaseBIPtr) += -Ibici_Vbiei;
*(here->HICUMbaseBIEmitEIPtr) += -Ibici_Vbiei;
// Stamp element: Iciei
*(here->HICUMcollCIBaseBIPtr) += Iciei_Vbiei;
*(here->HICUMemitEIEmitEIPtr) += Iciei_Vbiei;
*(here->HICUMcollCIEmitEIPtr) += -Iciei_Vbiei;
*(here->HICUMemitEIBaseBIPtr) += -Iciei_Vbiei;
*(here->HICUMcollCIBaseBIPtr) += Iciei_Vbici;
*(here->HICUMemitEICollCIPtr) += Iciei_Vbici;
*(here->HICUMcollCICollCIPtr) += -Iciei_Vbici;
*(here->HICUMemitEIBaseBIPtr) += -Iciei_Vbici;
if (nqs) {
*(here->HICUMcollCIXf2Ptr) += Iciei_Vxf2;
*(here->HICUMemitEIXf2Ptr) += -Iciei_Vxf2;
}
// Stamp element: Ibpci
*(here->HICUMbaseBPBaseBPPtr) += Ibpci_Vbpci;
*(here->HICUMcollCICollCIPtr) += Ibpci_Vbpci;
*(here->HICUMbaseBPCollCIPtr) += -Ibpci_Vbpci;
*(here->HICUMcollCIBaseBPPtr) += -Ibpci_Vbpci;
// Stamp element: Rcx
*(here->HICUMcollCollPtr) += Icic_Vcic;
*(here->HICUMcollCICollCIPtr) += Icic_Vcic;
*(here->HICUMcollCICollPtr) += -Icic_Vcic;
*(here->HICUMcollCollCIPtr) += -Icic_Vcic;
// Stamp element: Rbx
*(here->HICUMbaseBasePtr) += Ibbp_Vbbp;
*(here->HICUMbaseBPBaseBPPtr) += Ibbp_Vbbp;
*(here->HICUMbaseBPBasePtr) += -Ibbp_Vbbp;
*(here->HICUMbaseBaseBPPtr) += -Ibbp_Vbbp;
// Stamp element: Re
*(here->HICUMemitEmitPtr) += Ieie_Veie;
*(here->HICUMemitEIEmitEIPtr) += Ieie_Veie;
*(here->HICUMemitEIEmitPtr) += -Ieie_Veie;
*(here->HICUMemitEmitEIPtr) += -Ieie_Veie;
// Stamp element: Ibpbi
if (here->HICUMrbi>0.0) {
*(here->HICUMbaseBPBaseBPPtr) += Ibpbi_Vbpbi;
*(here->HICUMbaseBIBaseBIPtr) += Ibpbi_Vbpbi;
*(here->HICUMbaseBPBaseBIPtr) += -Ibpbi_Vbpbi;
*(here->HICUMbaseBIBaseBPPtr) += -Ibpbi_Vbpbi;
*(here->HICUMbaseBPBaseBIPtr) += Ibpbi_Vbiei;
*(here->HICUMbaseBIEmitEIPtr) += Ibpbi_Vbiei;
*(here->HICUMbaseBPEmitEIPtr) += -Ibpbi_Vbiei;
*(here->HICUMbaseBIBaseBIPtr) += -Ibpbi_Vbiei;
*(here->HICUMbaseBPBaseBIPtr) += Ibpbi_Vbici;
*(here->HICUMbaseBICollCIPtr) += Ibpbi_Vbici;
*(here->HICUMbaseBPCollCIPtr) += -Ibpbi_Vbici;
*(here->HICUMbaseBIBaseBIPtr) += -Ibpbi_Vbici;
};
// Stamp element: Isici
*(here->HICUMsubsSISubsSIPtr) += Isici_Vsici;
*(here->HICUMcollCICollCIPtr) += Isici_Vsici;
*(here->HICUMsubsSICollCIPtr) += -Isici_Vsici;
*(here->HICUMcollCISubsSIPtr) += -Isici_Vsici;;
// Stamp element: Ibpsi
*(here->HICUMbaseBPSubsSIPtr) += Ibpsi_Vsici;
*(here->HICUMsubsSICollCIPtr) += Ibpsi_Vsici;
*(here->HICUMbaseBPCollCIPtr) += -Ibpsi_Vsici;
*(here->HICUMsubsSISubsSIPtr) += -Ibpsi_Vsici;
*(here->HICUMbaseBPBaseBPPtr) += Ibpsi_Vbpci;
*(here->HICUMsubsSICollCIPtr) += Ibpsi_Vbpci;
*(here->HICUMbaseBPCollCIPtr) += -Ibpsi_Vbpci;
*(here->HICUMsubsSIBaseBPPtr) += -Ibpsi_Vbpci;;
// Stamp element: Rsu
*(here->HICUMsubsSubsPtr) += Isis_Vsis;
*(here->HICUMsubsSISubsSIPtr) += Isis_Vsis;
*(here->HICUMsubsSISubsPtr) += -Isis_Vsis;
*(here->HICUMsubsSubsSIPtr) += -Isis_Vsis;
if (nqs) {
//Ixf1
*(here->HICUMxf1BaseBIPtr) += +Ixf1_Vbiei;
*(here->HICUMxf1EmitEIPtr) += -Ixf1_Vbiei;
*(here->HICUMxf1BaseBIPtr) += +Ixf1_Vbici;
*(here->HICUMxf1CollCIPtr) += -Ixf1_Vbici;
*(here->HICUMxf1Xf2Ptr) += +Ixf1_Vxf2;
*(here->HICUMxf1Xf1Ptr) += +Ixf1_Vxf1;
//Ixf2
*(here->HICUMxf2BaseBIPtr) += +Ixf2_Vbiei;
*(here->HICUMxf2EmitEIPtr) += -Ixf2_Vbiei;
*(here->HICUMxf2BaseBIPtr) += +Ixf2_Vbici;
*(here->HICUMxf2CollCIPtr) += -Ixf2_Vbici;
*(here->HICUMxf2Xf2Ptr) += +Ixf2_Vxf2;
*(here->HICUMxf2Xf1Ptr) += +Ixf2_Vxf1;
//Ixf
*(here->HICUMxfBaseBIPtr) += +Ixf_Vbiei;
*(here->HICUMxfEmitEIPtr) += -Ixf_Vbiei;
*(here->HICUMxfBaseBIPtr) += +Ixf_Vbici;
*(here->HICUMxfCollCIPtr) += -Ixf_Vbici;
*(here->HICUMxfXfPtr) += +Ixf_Vxf;
}
////////////////////////////////////
////////// The complex part //////
////////////////////////////////////
//Qrbi
XQrbi_Vbpbi = *(ckt->CKTstate0 + here->HICUMcqrbi);
XQrbi_Vbiei = here->HICUMqrbi_Vbiei;
XQrbi_Vbici = here->HICUMqrbi_Vbici;
XQrbi_Vrth = here->HICUMqrbi_Vrth;
//Qjei
XQjei_Vbiei = *(ckt->CKTstate0 + here->HICUMcqjei);
XQjei_Vrth = here->HICUMqjei_Vrth;
//Qf
XQf_Vbiei = *(ckt->CKTstate0 + here->HICUMcqf);
XQf_Vbici = here->HICUMqf_Vbici;
XQf_Vrth = here->HICUMqf_Vrth;
XQf_Vxf = here->HICUMqf_Vxf;
//Qr
XQr_Vbici = *(ckt->CKTstate0 + here->HICUMcqr);
XQr_Vbiei = here->HICUMqr_Vbiei;
XQr_Vrth = here->HICUMqr_Vrth;
//Qjci
XQjci_Vbici = *(ckt->CKTstate0 + here->HICUMcqjci);
XQjci_Vrth = here->HICUMqjci_Vrth;
//Qjep
XQjep_Vbpei = *(ckt->CKTstate0 + here->HICUMcqjep);
XQjep_Vrth = here->HICUMqjep_Vrth;
//Qjcx_i
Xqjcx0_t_i_Vbci = *(ckt->CKTstate0 + here->HICUMcqcx0_t_i);
Xqjcx0_t_i_Vrth = here->HICUMqjcx0_i_Vrth;
//Qjcx_ii
Xqjcx0_t_ii_Vbpci = *(ckt->CKTstate0 + here->HICUMcqcx0_t_ii);
Xqjcx0_t_ii_Vrth = here->HICUMqjcx0_ii_Vrth;
//Qdsu
XQdsu_Vbpci = *(ckt->CKTstate0 + here->HICUMcqdsu);
XQdsu_Vsici = here->HICUMqdsu_Vsici;
XQdsu_Vrth = here->HICUMqdsu_Vrth;
//Qjs
XQjs_Vsici = *(ckt->CKTstate0 + here->HICUMcqjs);
XQjs_Vrth = here->HICUMqjs_Vrth;
//Qscp
XQscp_Vsc = *(ckt->CKTstate0 + here->HICUMcqscp);
XQscp_Vrth = here->HICUMqscp_Vrth;
//Qbepar1
XQbepar1_Vbe = *(ckt->CKTstate0 + here->HICUMcqbepar1);
//Qbepar2
XQbepar2_Vbpe = *(ckt->CKTstate0 + here->HICUMcqbepar2);
//Qbcpar1
XQbcpar1_Vbci = *(ckt->CKTstate0 + here->HICUMcqbcpar1);
//Qbcpar2
XQbcpar2_Vbpci = *(ckt->CKTstate0 + here->HICUMcqbcpar2);
//Qsu
XQsu_Vsis = *(ckt->CKTstate0 + here->HICUMcqsu);
//Qcth
XQcth_Vrth = *(ckt->CKTstate0 + here->HICUMcqcth);
//Qxf
XQxf_Vxf = *(ckt->CKTstate0 + here->HICUMcqxf);
XQxf1_Vxf1 = *(ckt->CKTstate0 + here->HICUMcqxf1);
XQxf2_Vxf2 = *(ckt->CKTstate0 + here->HICUMcqxf2);
//Qrbi f_bp=+ f_bi=-
if (here->HICUMrbi>0.0) {
*(here->HICUMbaseBPBaseBPPtr + 1) += XQrbi_Vbpbi*(s->imag);
*(here->HICUMbaseBPBaseBPPtr ) += XQrbi_Vbpbi*(s->real);
*(here->HICUMbaseBIBaseBIPtr + 1) += XQrbi_Vbpbi*(s->imag);
*(here->HICUMbaseBIBaseBIPtr ) += XQrbi_Vbpbi*(s->real);
*(here->HICUMbaseBPBaseBIPtr + 1) += -XQrbi_Vbpbi*(s->imag);
*(here->HICUMbaseBPBaseBIPtr ) += -XQrbi_Vbpbi*(s->real);
*(here->HICUMbaseBIBaseBPPtr + 1) += -XQrbi_Vbpbi*(s->imag);
*(here->HICUMbaseBIBaseBPPtr ) += -XQrbi_Vbpbi*(s->real);
*(here->HICUMbaseBPBaseBIPtr + 1) += XQrbi_Vbiei*(s->imag);
*(here->HICUMbaseBPBaseBIPtr ) += XQrbi_Vbiei*(s->real);
*(here->HICUMbaseBIEmitEIPtr + 1) += XQrbi_Vbiei*(s->imag);
*(here->HICUMbaseBIEmitEIPtr ) += XQrbi_Vbiei*(s->real);
*(here->HICUMbaseBPEmitEIPtr + 1) += -XQrbi_Vbiei*(s->imag);
*(here->HICUMbaseBPEmitEIPtr ) += -XQrbi_Vbiei*(s->real);
*(here->HICUMbaseBIBaseBIPtr + 1) += -XQrbi_Vbiei*(s->imag);
*(here->HICUMbaseBIBaseBIPtr ) += -XQrbi_Vbiei*(s->real);
*(here->HICUMbaseBPBaseBIPtr + 1) += XQrbi_Vbici*(s->imag);
*(here->HICUMbaseBPBaseBIPtr ) += XQrbi_Vbici*(s->real);
*(here->HICUMbaseBICollCIPtr + 1) += XQrbi_Vbici*(s->imag);
*(here->HICUMbaseBICollCIPtr ) += XQrbi_Vbici*(s->real);
*(here->HICUMbaseBPCollCIPtr + 1) += -XQrbi_Vbici*(s->imag);
*(here->HICUMbaseBPCollCIPtr ) += -XQrbi_Vbici*(s->real);
*(here->HICUMbaseBIBaseBIPtr + 1) += -XQrbi_Vbici*(s->imag);
*(here->HICUMbaseBIBaseBIPtr ) += -XQrbi_Vbici*(s->real);
};
//Qjei
*(here->HICUMbaseBIBaseBIPtr + 1) += XQjei_Vbiei*(s->imag);
*(here->HICUMbaseBIBaseBIPtr ) += XQjei_Vbiei*(s->real);
*(here->HICUMemitEIEmitEIPtr + 1) += XQjei_Vbiei*(s->imag);
*(here->HICUMemitEIEmitEIPtr ) += XQjei_Vbiei*(s->real);
*(here->HICUMbaseBIEmitEIPtr + 1) += -XQjei_Vbiei*(s->imag);
*(here->HICUMbaseBIEmitEIPtr ) += -XQjei_Vbiei*(s->real);
*(here->HICUMemitEIBaseBIPtr + 1) += -XQjei_Vbiei*(s->imag);
*(here->HICUMemitEIBaseBIPtr ) += -XQjei_Vbiei*(s->real);
//Qf f_Bi=+ f_Ei =-
*(here->HICUMbaseBIBaseBIPtr +1) += XQf_Vbiei*(s->imag);
*(here->HICUMbaseBIBaseBIPtr) += XQf_Vbiei*(s->real);
*(here->HICUMemitEIEmitEIPtr +1) += XQf_Vbiei*(s->imag);
*(here->HICUMemitEIEmitEIPtr) += XQf_Vbiei*(s->real);
*(here->HICUMbaseBIEmitEIPtr +1) += -XQf_Vbiei*(s->imag);
*(here->HICUMbaseBIEmitEIPtr) += -XQf_Vbiei*(s->real);
*(here->HICUMemitEIBaseBIPtr +1) += -XQf_Vbiei*(s->imag);
*(here->HICUMemitEIBaseBIPtr) += -XQf_Vbiei*(s->real);
*(here->HICUMbaseBIBaseBIPtr +1) += XQf_Vbici*(s->imag);
*(here->HICUMbaseBIBaseBIPtr) += XQf_Vbici*(s->real);
*(here->HICUMemitEICollCIPtr +1) += XQf_Vbici*(s->imag);
*(here->HICUMemitEICollCIPtr) += XQf_Vbici*(s->real);
*(here->HICUMbaseBICollCIPtr +1) += -XQf_Vbici*(s->imag);
*(here->HICUMbaseBICollCIPtr) += -XQf_Vbici*(s->real);
*(here->HICUMemitEIBaseBIPtr +1) += -XQf_Vbici*(s->imag);
*(here->HICUMemitEIBaseBIPtr) += -XQf_Vbici*(s->real);
if (nqs) {
*(here->HICUMbaseBIXfPtr +1) += XQf_Vxf*(s->imag);
*(here->HICUMbaseBIXfPtr ) += XQf_Vxf*(s->real);
*(here->HICUMemitEIXfPtr +1) += -XQf_Vxf*(s->imag);
*(here->HICUMemitEIXfPtr ) += -XQf_Vxf*(s->real);
}
//Qjci
*(here->HICUMbaseBIBaseBIPtr +1) += XQjci_Vbici*(s->imag);
*(here->HICUMbaseBIBaseBIPtr) += XQjci_Vbici*(s->real);
*(here->HICUMcollCICollCIPtr +1) += XQjci_Vbici*(s->imag);
*(here->HICUMcollCICollCIPtr) += XQjci_Vbici*(s->real);
*(here->HICUMcollCIBaseBIPtr +1) += -XQjci_Vbici*(s->imag);
*(here->HICUMcollCIBaseBIPtr) += -XQjci_Vbici*(s->real);
*(here->HICUMbaseBICollCIPtr +1) += -XQjci_Vbici*(s->imag);
*(here->HICUMbaseBICollCIPtr) += -XQjci_Vbici*(s->real);
//Qr f_bi = + f_ci=-
*(here->HICUMbaseBIBaseBIPtr +1) += XQr_Vbici*(s->imag);
*(here->HICUMbaseBIBaseBIPtr) += XQr_Vbici*(s->real);
*(here->HICUMcollCICollCIPtr +1) += XQr_Vbici*(s->imag);
*(here->HICUMcollCICollCIPtr) += XQr_Vbici*(s->real);
*(here->HICUMcollCIBaseBIPtr +1) += -XQr_Vbici*(s->imag);
*(here->HICUMcollCIBaseBIPtr) += -XQr_Vbici*(s->real);
*(here->HICUMbaseBICollCIPtr +1) += -XQr_Vbici*(s->imag);
*(here->HICUMbaseBICollCIPtr) += -XQr_Vbici*(s->real);
*(here->HICUMbaseBIBaseBIPtr +1) += XQr_Vbiei*(s->imag);
*(here->HICUMbaseBIBaseBIPtr) += XQr_Vbiei*(s->real);
*(here->HICUMcollCIEmitEIPtr +1) += XQr_Vbiei*(s->imag);
*(here->HICUMcollCIEmitEIPtr) += XQr_Vbiei*(s->real);
*(here->HICUMcollCIBaseBIPtr +1) += -XQr_Vbiei*(s->imag);
*(here->HICUMcollCIBaseBIPtr) += -XQr_Vbiei*(s->real);
*(here->HICUMbaseBIEmitEIPtr +1) += -XQr_Vbiei*(s->imag);
*(here->HICUMbaseBIEmitEIPtr) += -XQr_Vbiei*(s->real);
//Qjep
*(here->HICUMbaseBPBaseBPPtr +1) += XQjep_Vbpei*(s->imag);
*(here->HICUMbaseBPBaseBPPtr) += XQjep_Vbpei*(s->real);
*(here->HICUMemitEIEmitEIPtr +1) += XQjep_Vbpei*(s->imag);
*(here->HICUMemitEIEmitEIPtr) += XQjep_Vbpei*(s->real);
*(here->HICUMbaseBPEmitEIPtr +1) += -XQjep_Vbpei*(s->imag);
*(here->HICUMbaseBPEmitEIPtr) += -XQjep_Vbpei*(s->real);
*(here->HICUMemitEIBaseBPPtr +1) += -XQjep_Vbpei*(s->imag);
*(here->HICUMemitEIBaseBPPtr) += -XQjep_Vbpei*(s->real);
//Qjcx_i
*(here->HICUMbaseBasePtr +1) += Xqjcx0_t_i_Vbci*(s->imag);
*(here->HICUMbaseBasePtr) += Xqjcx0_t_i_Vbci*(s->real);
*(here->HICUMcollCICollCIPtr +1) += Xqjcx0_t_i_Vbci*(s->imag);
*(here->HICUMcollCICollCIPtr) += Xqjcx0_t_i_Vbci*(s->real);
*(here->HICUMbaseCollCIPtr +1) += -Xqjcx0_t_i_Vbci*(s->imag);
*(here->HICUMbaseCollCIPtr) += -Xqjcx0_t_i_Vbci*(s->real);
*(here->HICUMcollCIBasePtr +1) += -Xqjcx0_t_i_Vbci*(s->imag);
*(here->HICUMcollCIBasePtr) += -Xqjcx0_t_i_Vbci*(s->real);
//Qjcx_ii
*(here->HICUMbaseBPBaseBPPtr +1) += Xqjcx0_t_ii_Vbpci*(s->imag);
*(here->HICUMbaseBPBaseBPPtr) += Xqjcx0_t_ii_Vbpci*(s->real);
*(here->HICUMcollCICollCIPtr +1) += Xqjcx0_t_ii_Vbpci*(s->imag);
*(here->HICUMcollCICollCIPtr) += Xqjcx0_t_ii_Vbpci*(s->real);
*(here->HICUMbaseBPCollCIPtr +1) += -Xqjcx0_t_ii_Vbpci*(s->imag);
*(here->HICUMbaseBPCollCIPtr) += -Xqjcx0_t_ii_Vbpci*(s->real);
*(here->HICUMcollCIBaseBPPtr +1) += -Xqjcx0_t_ii_Vbpci*(s->imag);
*(here->HICUMcollCIBaseBPPtr) += -Xqjcx0_t_ii_Vbpci*(s->real);
//Qdsu f_bp=+ f_ci=-
*(here->HICUMbaseBPBaseBPPtr +1) += XQdsu_Vbpci*(s->imag);
*(here->HICUMbaseBPBaseBPPtr) += XQdsu_Vbpci*(s->real);
*(here->HICUMcollCICollCIPtr +1) += XQdsu_Vbpci*(s->imag);
*(here->HICUMcollCICollCIPtr) += XQdsu_Vbpci*(s->real);
*(here->HICUMbaseBPCollCIPtr +1) += -XQdsu_Vbpci*(s->imag);
*(here->HICUMbaseBPCollCIPtr) += -XQdsu_Vbpci*(s->real);
*(here->HICUMcollCIBaseBPPtr +1) += -XQdsu_Vbpci*(s->imag);
*(here->HICUMcollCIBaseBPPtr) += -XQdsu_Vbpci*(s->real);
*(here->HICUMbaseBPSubsSIPtr +1) += XQdsu_Vsici*(s->imag);
*(here->HICUMbaseBPSubsSIPtr) += XQdsu_Vsici*(s->real);
*(here->HICUMcollCICollCIPtr +1) += XQdsu_Vsici*(s->imag);
*(here->HICUMcollCICollCIPtr) += XQdsu_Vsici*(s->real);
*(here->HICUMbaseBPCollCIPtr +1) += -XQdsu_Vsici*(s->imag);
*(here->HICUMbaseBPCollCIPtr) += -XQdsu_Vsici*(s->real);
*(here->HICUMcollCISubsSIPtr +1) += -XQdsu_Vsici*(s->imag);
*(here->HICUMcollCISubsSIPtr) += -XQdsu_Vsici*(s->real);
//Qjs
*(here->HICUMsubsSISubsSIPtr +1) += XQjs_Vsici*(s->imag);
*(here->HICUMsubsSISubsSIPtr) += XQjs_Vsici*(s->real);
*(here->HICUMcollCICollCIPtr +1) += XQjs_Vsici*(s->imag);
*(here->HICUMcollCICollCIPtr) += XQjs_Vsici*(s->real);
*(here->HICUMsubsSICollCIPtr +1) += -XQjs_Vsici*(s->imag);
*(here->HICUMsubsSICollCIPtr) += -XQjs_Vsici*(s->real);
*(here->HICUMcollCISubsSIPtr +1) += -XQjs_Vsici*(s->imag);
*(here->HICUMcollCISubsSIPtr) += -XQjs_Vsici*(s->real);
//Qscp
*(here->HICUMsubsSubsPtr + 1) += XQscp_Vsc*(s->imag);
*(here->HICUMsubsSubsPtr ) += XQscp_Vsc*(s->real);
*(here->HICUMcollCollPtr + 1) += XQscp_Vsc*(s->imag);
*(here->HICUMcollCollPtr ) += XQscp_Vsc*(s->real);
*(here->HICUMcollSubsPtr + 1) += -XQscp_Vsc*(s->imag);
*(here->HICUMcollSubsPtr ) += -XQscp_Vsc*(s->real);
*(here->HICUMsubsCollPtr + 1) += -XQscp_Vsc*(s->imag);
*(here->HICUMsubsCollPtr ) += -XQscp_Vsc*(s->real);
//Qbepar1
*(here->HICUMbaseBasePtr + 1) += XQbepar1_Vbe*(s->imag);
*(here->HICUMbaseBasePtr ) += XQbepar1_Vbe*(s->real);
*(here->HICUMemitEmitPtr + 1) += XQbepar1_Vbe*(s->imag);
*(here->HICUMemitEmitPtr ) += XQbepar1_Vbe*(s->real);
*(here->HICUMbaseEmitPtr + 1) += -XQbepar1_Vbe*(s->imag);
*(here->HICUMbaseEmitPtr ) += -XQbepar1_Vbe*(s->real);
*(here->HICUMemitBasePtr + 1) += -XQbepar1_Vbe*(s->imag);
*(here->HICUMemitBasePtr ) += -XQbepar1_Vbe*(s->real);
//Qbepar2
*(here->HICUMbaseBPBaseBPPtr + 1) += XQbepar2_Vbpe*(s->imag);
*(here->HICUMbaseBPBaseBPPtr ) += XQbepar2_Vbpe*(s->real);
*(here->HICUMemitEmitPtr + 1) += XQbepar2_Vbpe*(s->imag);
*(here->HICUMemitEmitPtr ) += XQbepar2_Vbpe*(s->real);
*(here->HICUMemitBaseBPPtr + 1) += -XQbepar2_Vbpe*(s->imag);
*(here->HICUMemitBaseBPPtr ) += -XQbepar2_Vbpe*(s->real);
*(here->HICUMbaseBPEmitPtr + 1) += -XQbepar2_Vbpe*(s->imag);
*(here->HICUMbaseBPEmitPtr ) += -XQbepar2_Vbpe*(s->real);
//Qbcpar1
*(here->HICUMbaseBasePtr + 1) += XQbcpar1_Vbci*(s->imag);
*(here->HICUMbaseBasePtr ) += XQbcpar1_Vbci*(s->real);
*(here->HICUMcollCICollCIPtr + 1) += XQbcpar1_Vbci*(s->imag);
*(here->HICUMcollCICollCIPtr ) += XQbcpar1_Vbci*(s->real);
*(here->HICUMbaseCollCIPtr + 1) += -XQbcpar1_Vbci*(s->imag);
*(here->HICUMbaseCollCIPtr ) += -XQbcpar1_Vbci*(s->real);
*(here->HICUMcollCIBasePtr + 1) += -XQbcpar1_Vbci*(s->imag);
*(here->HICUMcollCIBasePtr ) += -XQbcpar1_Vbci*(s->real);
//Qbcpar2
*(here->HICUMbaseBPBaseBPPtr +1) += XQbcpar2_Vbpci*(s->imag);
*(here->HICUMbaseBPBaseBPPtr) += XQbcpar2_Vbpci*(s->real);
*(here->HICUMcollCICollCIPtr +1) += XQbcpar2_Vbpci*(s->imag);
*(here->HICUMcollCICollCIPtr) += XQbcpar2_Vbpci*(s->real);
*(here->HICUMbaseBPCollCIPtr +1) += -XQbcpar2_Vbpci*(s->imag);
*(here->HICUMbaseBPCollCIPtr) += -XQbcpar2_Vbpci*(s->real);
*(here->HICUMcollCIBaseBPPtr +1) += -XQbcpar2_Vbpci*(s->imag);
*(here->HICUMcollCIBaseBPPtr) += -XQbcpar2_Vbpci*(s->real);
//Qsu
*(here->HICUMsubsSubsPtr + 1) += XQsu_Vsis*(s->imag);
*(here->HICUMsubsSubsPtr ) += XQsu_Vsis*(s->real);
*(here->HICUMsubsSISubsSIPtr + 1) += XQsu_Vsis*(s->imag);
*(here->HICUMsubsSISubsSIPtr ) += XQsu_Vsis*(s->real);
*(here->HICUMsubsSISubsPtr + 1) += -XQsu_Vsis*(s->imag);
*(here->HICUMsubsSISubsPtr ) += -XQsu_Vsis*(s->real);
*(here->HICUMsubsSubsSIPtr + 1) += -XQsu_Vsis*(s->imag);
*(here->HICUMsubsSubsSIPtr ) += -XQsu_Vsis*(s->real);
if (nqs) {
//Qxf1
*(here->HICUMxf1Xf1Ptr + 1) += +XQxf1_Vxf1*(s->imag);
*(here->HICUMxf1Xf1Ptr) += +XQxf1_Vxf1*(s->real);
//Qxf2
*(here->HICUMxf2Xf2Ptr + 1) += +XQxf2_Vxf2*(s->imag);
*(here->HICUMxf2Xf2Ptr ) += +XQxf2_Vxf2*(s->real);
//Qxf
*(here->HICUMxfXfPtr + 1) += +XQxf_Vxf*(s->imag);
*(here->HICUMxfXfPtr ) += +XQxf_Vxf*(s->real);
}
// Stamps with SH
if (selfheat) {
// Stamp element: Ibiei f_Bi = + f_Ei = -
*(here->HICUMbaseBItempPtr) += Ibiei_Vrth;
*(here->HICUMemitEItempPtr) += -Ibiei_Vrth;
// Stamp element: Ibpei f_Bp = + f_Ei = -
// with respect to Potential Vrth
*(here->HICUMbaseBPtempPtr) += Ibpei_Vrth;
*(here->HICUMemitEItempPtr) += -Ibpei_Vrth;
// Stamp element: Ibici f_Bi = + f_Ci = -
*(here->HICUMbaseBItempPtr) += Ibici_Vrth;
*(here->HICUMcollCItempPtr) += -Ibici_Vrth;
// Stamp element: Iciei f_Ci = + f_Ei = -
*(here->HICUMcollCItempPtr) += Iciei_Vrth;
*(here->HICUMemitEItempPtr) += -Iciei_Vrth;
// Stamp element: Ibpci f_Bp = + f_Ci = -
*(here->HICUMbaseBPtempPtr) += Ibpci_Vrth;
*(here->HICUMcollCItempPtr) += -Ibpci_Vrth;
// Stamp element: Rcx f_Ci = + f_C = -
*(here->HICUMcollCItempPtr) += Icic_Vrth;
*(here->HICUMcollTempPtr) += -Icic_Vrth;
// Stamp element: Rbx f_B = + f_Bp = -
*(here->HICUMbaseTempPtr) += Ibbp_Vrth;
*(here->HICUMbaseBPtempPtr) += -Ibbp_Vrth;
// Stamp element: Re f_Ei = + f_E = -
*(here->HICUMemitEItempPtr) += Ieie_Vrth;
*(here->HICUMemitTempPtr) += -Ieie_Vrth;
if (here->HICUMrbi>0.0) {
// Stamp element: Rbi f_Bp = + f_Bi = -
*(here->HICUMbaseBPtempPtr) += Ibpbi_Vrth;
*(here->HICUMbaseBItempPtr) += -Ibpbi_Vrth;
};
// Stamp element: Isici f_Si = + f_Ci = -
*(here->HICUMsubsSItempPtr) += Isici_Vrth;
*(here->HICUMcollCItempPtr) += -Isici_Vrth;
// Branch: bpsi, Stamp element: Its
*(here->HICUMbaseBPtempPtr) += Ibpsi_Vrth;
*(here->HICUMsubsSItempPtr) += -Ibpsi_Vrth;
if (nqs) {
// Stamp element: Ixf f_xf = +
*(here->HICUMxfTempPtr) += Ixf_Vrth;
// Stamp element: Ixf1 f_xf1 = +
*(here->HICUMxf1TempPtr) += Ixf1_Vrth;
// Stamp element: Ixf2 f_xf2 = +
*(here->HICUMxf2TempPtr) += Ixf2_Vrth;
}
// Stamp element: Rth f_T = +
*(here->HICUMtempTempPtr) += Irth_Vrth;
// Stamp element: Ith f_T = - Ith
// with respect to Potential Vrth
*(here->HICUMtempTempPtr) += -Ith_Vrth;
// with respect to Potential Vbiei
*(here->HICUMtempBaseBIPtr) += -Ith_Vbiei;
*(here->HICUMtempEmitEIPtr) += +Ith_Vbiei;
// with respect to Potential Vbici
*(here->HICUMtempBaseBIPtr) += -Ith_Vbici;
*(here->HICUMtempCollCIPtr) += +Ith_Vbici;
// with respect to Potential Vciei
*(here->HICUMtempCollCIPtr) += -Ith_Vciei;
*(here->HICUMtempEmitEIPtr) += +Ith_Vciei;
// with respect to Potential Vbpei
*(here->HICUMtempBaseBPPtr) += -Ith_Vbpei;
*(here->HICUMtempEmitEIPtr) += +Ith_Vbpei;
// with respect to Potential Vbpci
*(here->HICUMtempBaseBPPtr) += -Ith_Vbpci;
*(here->HICUMtempCollCIPtr) += +Ith_Vbpci;
// with respect to Potential Vsici
*(here->HICUMtempSubsSIPtr) += -Ith_Vsici;
*(here->HICUMtempCollCIPtr) += +Ith_Vsici;
// with respect to Potential Vbpbi
*(here->HICUMtempBaseBPPtr) += -Ith_Vbpbi;
*(here->HICUMtempBaseBIPtr) += +Ith_Vbpbi;
// with respect to Potential Vcic
*(here->HICUMtempCollCIPtr) += -Ith_Vcic;
*(here->HICUMtempCollPtr) += +Ith_Vcic;
// with respect to Potential Vbbp
*(here->HICUMtempBasePtr) += -Ith_Vbbp;
*(here->HICUMtempBaseBPPtr) += +Ith_Vbbp;
// with respect to Potential Veie
*(here->HICUMtempEmitEIPtr) += -Ith_Veie;
*(here->HICUMtempEmitPtr) += +Ith_Veie;
//the charges
*(here->HICUMbaseBItempPtr + 1) += +XQrbi_Vrth*(s->imag);
*(here->HICUMbaseBItempPtr ) += +XQrbi_Vrth*(s->real);
*(here->HICUMbaseBPtempPtr + 1) += -XQrbi_Vrth*(s->imag);
*(here->HICUMbaseBPtempPtr ) += -XQrbi_Vrth*(s->real);
*(here->HICUMbaseBItempPtr + 1) += +XQjei_Vrth*(s->imag);
*(here->HICUMbaseBItempPtr ) += +XQjei_Vrth*(s->real);
*(here->HICUMemitEItempPtr + 1) += -XQjei_Vrth*(s->imag);
*(here->HICUMemitEItempPtr ) += -XQjei_Vrth*(s->real);
*(here->HICUMbaseBItempPtr + 1) += +XQf_Vrth*(s->imag);
*(here->HICUMbaseBItempPtr ) += +XQf_Vrth*(s->real);
*(here->HICUMemitEItempPtr + 1) += -XQf_Vrth*(s->imag);
*(here->HICUMemitEItempPtr ) += -XQf_Vrth*(s->real);
*(here->HICUMbaseBItempPtr + 1) += +XQr_Vrth*(s->imag);
*(here->HICUMbaseBItempPtr ) += +XQr_Vrth*(s->real);
*(here->HICUMcollCItempPtr + 1) += -XQr_Vrth*(s->imag);
*(here->HICUMcollCItempPtr ) += -XQr_Vrth*(s->real);
*(here->HICUMbaseBItempPtr + 1) += +XQjci_Vrth*(s->imag);
*(here->HICUMbaseBItempPtr ) += +XQjci_Vrth*(s->real);
*(here->HICUMcollCItempPtr + 1) += -XQjci_Vrth*(s->imag);
*(here->HICUMcollCItempPtr ) += -XQjci_Vrth*(s->real);
*(here->HICUMbaseBPtempPtr + 1) += +XQjep_Vrth*(s->imag);
*(here->HICUMbaseBPtempPtr ) += +XQjep_Vrth*(s->real);
*(here->HICUMemitEItempPtr + 1) += -XQjep_Vrth*(s->imag);
*(here->HICUMemitEItempPtr ) += -XQjep_Vrth*(s->real);
*(here->HICUMbaseTempPtr + 1) += +Xqjcx0_t_i_Vrth*(s->imag);
*(here->HICUMbaseTempPtr ) += +Xqjcx0_t_i_Vrth*(s->real);
*(here->HICUMcollCItempPtr + 1) += -Xqjcx0_t_i_Vrth*(s->imag);
*(here->HICUMcollCItempPtr ) += -Xqjcx0_t_i_Vrth*(s->real);
*(here->HICUMbaseBPtempPtr + 1) += +Xqjcx0_t_ii_Vrth*(s->imag);
*(here->HICUMbaseBPtempPtr ) += +Xqjcx0_t_ii_Vrth*(s->real);
*(here->HICUMcollCItempPtr + 1) += -Xqjcx0_t_ii_Vrth*(s->imag);
*(here->HICUMcollCItempPtr ) += -Xqjcx0_t_ii_Vrth*(s->real);
*(here->HICUMbaseBPtempPtr + 1) += +XQdsu_Vrth*(s->imag);
*(here->HICUMbaseBPtempPtr ) += +XQdsu_Vrth*(s->real);
*(here->HICUMcollCItempPtr + 1) += -XQdsu_Vrth*(s->imag);
*(here->HICUMcollCItempPtr ) += -XQdsu_Vrth*(s->real);
*(here->HICUMsubsSItempPtr + 1) += +XQjs_Vrth*(s->imag);
*(here->HICUMsubsSItempPtr ) += +XQjs_Vrth*(s->real);
*(here->HICUMcollCItempPtr + 1) += -XQjs_Vrth*(s->imag);
*(here->HICUMcollCItempPtr ) += -XQjs_Vrth*(s->real);
*(here->HICUMsubsTempPtr + 1) += +XQscp_Vrth*(s->imag);
*(here->HICUMsubsTempPtr ) += +XQscp_Vrth*(s->real);
*(here->HICUMcollTempPtr + 1) += -XQscp_Vrth*(s->imag);
*(here->HICUMcollTempPtr ) += -XQscp_Vrth*(s->real);
*(here->HICUMtempTempPtr + 1) += +XQcth_Vrth*(s->imag);
*(here->HICUMtempTempPtr ) += +XQcth_Vrth*(s->real);
}
}
}
return(OK);
}

863
src/spicelib/devices/hicum2/hicum2setup.c

@ -0,0 +1,863 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine should only be called when circuit topology
* changes, since its computations do not depend on most
* device or model parameters, only on topology (as
* affected by emitter, collector, and base resistances)
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/smpdefs.h"
#include "hicum2defs.h"
#include "ngspice/const.h"
#include "ngspice/sperror.h"
#include "ngspice/ifsim.h"
#include "ngspice/suffix.h"
int
HICUMsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
/* load the HICUM structure with those pointers needed later
* for fast matrix loading
*/
{
HICUMmodel *model = (HICUMmodel*)inModel;
HICUMinstance *here;
int error;
CKTnode *tmp;
/* loop through all the transistor models */
for( ; model != NULL; model = HICUMnextModel(model)) {
//Circuit simulator specific parameters
if(model->HICUMtype != NPN && model->HICUMtype != PNP)
model->HICUMtype = NPN;
if(!model->HICUMtnomGiven)
model->HICUMtnom = ckt->CKTnomTemp;
if (!model->HICUMversionGiven)
model->HICUMversion = copy("2.4.0");
//Transfer current
if(!model->HICUMc10Given)
model->HICUMc10 = 2e-30;
if(!model->HICUMqp0Given)
model->HICUMqp0 = 2e-14;
if(!model->HICUMichGiven)
model->HICUMich = 0.0;
if(!model->HICUMhf0Given)
model->HICUMhf0 = 1.0;
if(!model->HICUMhfeGiven)
model->HICUMhfe = 1.0;
if(!model->HICUMhfcGiven)
model->HICUMhfc = 1.0;
if(!model->HICUMhjeiGiven)
model->HICUMhjei = 1.0;
if(!model->HICUMahjeiGiven)
model->HICUMahjei = 0.0;
if(!model->HICUMrhjeiGiven)
model->HICUMrhjei = 1.0;
if(!model->HICUMhjciGiven)
model->HICUMhjci = 1.0;
//Base-Emitter diode;
if(!model->HICUMibeisGiven)
model->HICUMibeis = 1e-18;
if(!model->HICUMmbeiGiven)
model->HICUMmbei = 1.0;
if(!model->HICUMireisGiven)
model->HICUMireis = 0.0;
if(!model->HICUMmreiGiven)
model->HICUMmrei = 2.0;
if(!model->HICUMibepsGiven)
model->HICUMibeps = 0.0;
if(!model->HICUMmbepGiven)
model->HICUMmbep = 1.0;
if(!model->HICUMirepsGiven)
model->HICUMireps = 0.0;
if(!model->HICUMmrepGiven)
model->HICUMmrep = 2.0;
if(!model->HICUMmcfGiven)
model->HICUMmcf = 1.0;
//Transit time for excess recombination current at b-c barrier
if(!model->HICUMtbhrecGiven)
model->HICUMtbhrec = 0.0;
//Base-Collector diode currents
if(!model->HICUMibcisGiven)
model->HICUMibcis = 1e-16;
if(!model->HICUMmbciGiven)
model->HICUMmbci = 1.0;
if(!model->HICUMibcxsGiven)
model->HICUMibcxs = 0.0;
if(!model->HICUMmbcxGiven)
model->HICUMmbcx = 1.0;
//Base-Emitter tunneling current
if(!model->HICUMibetsGiven)
model->HICUMibets = 0.0;
if(!model->HICUMabetGiven)
model->HICUMabet = 40.0;
if(!model->HICUMtunodeGiven)
model->HICUMtunode = 1;
//Base-Collector avalanche current
if(!model->HICUMfavlGiven)
model->HICUMfavl = 0.0;
if(!model->HICUMqavlGiven)
model->HICUMqavl = 0.0;
if(!model->HICUMkavlGiven)
model->HICUMkavl = 0.0;
if(!model->HICUMalfavGiven)
model->HICUMalfav = 0.0;
if(!model->HICUMalqavGiven)
model->HICUMalqav = 0.0;
if(!model->HICUMalkavGiven)
model->HICUMalkav = 0.0;
//Series resistances
if(!model->HICUMrbi0Given)
model->HICUMrbi0 = 0.0;
if(!model->HICUMrbxGiven)
model->HICUMrbx = 0.0;
if(!model->HICUMfgeoGiven)
model->HICUMfgeo = 0.6557;
if(!model->HICUMfdqr0Given)
model->HICUMfdqr0 = 0.0;
if(!model->HICUMfcrbiGiven)
model->HICUMfcrbi = 0.0;
if(!model->HICUMfqiGiven)
model->HICUMfqi = 1.0;
if(!model->HICUMreGiven)
model->HICUMre = 0.0;
if(!model->HICUMrcxGiven)
model->HICUMrcx = 0.0;
//Substrate transistor
if(!model->HICUMitssGiven)
model->HICUMitss = 0.0;
if(!model->HICUMmsfGiven)
model->HICUMmsf = 1.0;
if(!model->HICUMiscsGiven)
model->HICUMiscs = 0.0;
if(!model->HICUMmscGiven)
model->HICUMmsc = 1.0;
if(!model->HICUMtsfGiven)
model->HICUMtsf = 0.0;
//Intra-device substrate coupling
if(!model->HICUMrsuGiven)
model->HICUMrsu = 0.0;
if(!model->HICUMcsuGiven)
model->HICUMcsu = 0.0;
//Depletion Capacitances
if(!model->HICUMcjei0Given)
model->HICUMcjei0 = 1.0e-20;
if(!model->HICUMvdeiGiven)
model->HICUMvdei = 0.9;
if(!model->HICUMzeiGiven)
model->HICUMzei = 0.5;
if(!model->HICUMajeiGiven)
model->HICUMajei = 2.5;
if(!model->HICUMcjep0Given)
model->HICUMcjep0 = 1.0e-20;
if(!model->HICUMvdepGiven)
model->HICUMvdep = 0.9;
if(!model->HICUMzepGiven)
model->HICUMzep = 0.5;
if(!model->HICUMajepGiven)
model->HICUMajep = 2.5;
if(!model->HICUMcjci0Given)
model->HICUMcjci0 = 1.0e-20;
if(!model->HICUMvdciGiven)
model->HICUMvdci = 0.7;
if(!model->HICUMzciGiven)
model->HICUMzci = 0.4;
if(!model->HICUMvptciGiven)
model->HICUMvptci = 100.0;
if(!model->HICUMcjcx0Given)
model->HICUMcjcx0 = 1.0e-20;
if(!model->HICUMvdcxGiven)
model->HICUMvdcx = 0.7;
if(!model->HICUMzcxGiven)
model->HICUMzcx = 0.4;
if(!model->HICUMvptcxGiven)
model->HICUMvptcx = 100.0;
if(!model->HICUMfbcparGiven)
model->HICUMfbcpar = 0.0;
if(!model->HICUMfbeparGiven)
model->HICUMfbepar = 1.0;
if(!model->HICUMcjs0Given)
model->HICUMcjs0 = 0.0;
if(!model->HICUMvdsGiven)
model->HICUMvds = 0.6;
if(!model->HICUMzsGiven)
model->HICUMzs = 0.5;
if(!model->HICUMvptsGiven)
model->HICUMvpts = 100.0;
if(!model->HICUMcscp0Given)
model->HICUMcscp0 = 0.0;
if(!model->HICUMvdspGiven)
model->HICUMvdsp = 0.6;
if(!model->HICUMzspGiven)
model->HICUMzsp = 0.5;
if(!model->HICUMvptspGiven)
model->HICUMvptsp = 100.0;
//Diffusion Capacitances
if(!model->HICUMt0Given)
model->HICUMt0 = 0.0;
if(!model->HICUMdt0hGiven)
model->HICUMdt0h = 0.0;
if(!model->HICUMtbvlGiven)
model->HICUMtbvl = 0.0;
if(!model->HICUMtef0Given)
model->HICUMtef0 = 0.0;
if(!model->HICUMgtfeGiven)
model->HICUMgtfe = 1.0;
if(!model->HICUMthcsGiven)
model->HICUMthcs = 0.0;
if(!model->HICUMahcGiven)
model->HICUMahc = 0.1;
if(!model->HICUMfthcGiven)
model->HICUMfthc = 0.0;
if(!model->HICUMrci0Given)
model->HICUMrci0 = 150;
if(!model->HICUMvlimGiven)
model->HICUMvlim = 0.5;
if(!model->HICUMvcesGiven)
model->HICUMvces = 0.1;
if(!model->HICUMvptGiven)
model->HICUMvpt = 100.0;
if(!model->HICUMaickGiven)
model->HICUMaick = 1.0e-03;
if(!model->HICUMdelckGiven)
model->HICUMdelck = 2.0;
if(!model->HICUMtrGiven)
model->HICUMtr = 0.0;
if(!model->HICUMvcbarGiven)
model->HICUMvcbar = 0.0;
if(!model->HICUMicbarGiven)
model->HICUMicbar = 0.0;
if(!model->HICUMacbarGiven)
model->HICUMacbar = 0.01;
//Isolation Capacitances
if(!model->HICUMcbeparGiven)
model->HICUMcbepar = 0.0;
if(!model->HICUMcbcparGiven)
model->HICUMcbcpar = 0.0;
//Non-quasi-static Effect
if(!model->HICUMalqfGiven)
model->HICUMalqf = 0.167;
if(!model->HICUMalitGiven)
model->HICUMalit = 0.333;
if(!model->HICUMflnqsGiven)
model->HICUMflnqs = 0;
//Noise
if(!model->HICUMkfGiven)
model->HICUMkf = 0.0;
if(!model->HICUMafGiven)
model->HICUMaf = 2.0;
if(!model->HICUMcfbeGiven)
model->HICUMcfbe = -1;
if(!model->HICUMflconoGiven)
model->HICUMflcono = 0;
if(!model->HICUMkfreGiven)
model->HICUMkfre = 0.0;
if(!model->HICUMafreGiven)
model->HICUMafre = 2.0;
//Lateral Geometry Scaling (at high current densities)
if(!model->HICUMlatbGiven)
model->HICUMlatb = 0.0;
if(!model->HICUMlatlGiven)
model->HICUMlatl = 0.0;
//Temperature dependence
if(!model->HICUMvgbGiven)
model->HICUMvgb = 1.17;
if(!model->HICUMalt0Given)
model->HICUMalt0 = 0.0;
if(!model->HICUMkt0Given)
model->HICUMkt0 = 0.0;
if(!model->HICUMzetaciGiven)
model->HICUMzetaci = 0.0;
if(!model->HICUMalvsGiven)
model->HICUMalvs = 0.0;
if(!model->HICUMalcesGiven)
model->HICUMalces = 0.0;
if(!model->HICUMzetarbiGiven)
model->HICUMzetarbi = 0.0;
if(!model->HICUMzetarbxGiven)
model->HICUMzetarbx = 0.0;
if(!model->HICUMzetarcxGiven)
model->HICUMzetarcx = 0.0;
if(!model->HICUMzetareGiven)
model->HICUMzetare = 0.0;
if(!model->HICUMzetacxGiven)
model->HICUMzetacx = 1.0;
if(!model->HICUMvgeGiven)
model->HICUMvge = 1.17;
if(!model->HICUMvgcGiven)
model->HICUMvgc = 1.17;
if(!model->HICUMvgsGiven)
model->HICUMvgs = 1.17;
if(!model->HICUMf1vgGiven)
model->HICUMf1vg = -1.02377e-4;
if(!model->HICUMf2vgGiven)
model->HICUMf2vg = 4.3215e-4;
if(!model->HICUMzetactGiven)
model->HICUMzetact = 3.0;
if(!model->HICUMzetabetGiven)
model->HICUMzetabet = 3.5;
if(!model->HICUMalbGiven)
model->HICUMalb = 0.0;
if(!model->HICUMdvgbeGiven)
model->HICUMdvgbe = 0.0;
if(!model->HICUMzetahjeiGiven)
model->HICUMzetahjei = 1.0;
if(!model->HICUMzetavgbeGiven)
model->HICUMzetavgbe = 1.0;
//Self-Heating
if(!model->HICUMflshGiven)
model->HICUMflsh = 0;
if(!model->HICUMrthGiven)
model->HICUMrth = 0.0;
if(!model->HICUMzetarthGiven)
model->HICUMzetarth = 0.0;
if(!model->HICUMalrthGiven)
model->HICUMalrth = 0.0;
if(!model->HICUMcthGiven)
model->HICUMcth = 0.0;
if((model->HICUMrthGiven) && (model->HICUMcth < 1e-12))
model->HICUMcth = 1e-12;
//Compatibility with V2.1
if(!model->HICUMflcompGiven)
model->HICUMflcomp = 0.0;
if(!model->HICUMvbeMaxGiven)
model->HICUMvbeMax = 1e99;
if(!model->HICUMvbcMaxGiven)
model->HICUMvbcMax = 1e99;
if(!model->HICUMvceMaxGiven)
model->HICUMvceMax = 1e99;
int selfheat = (((model->HICUMflsh == 1) || (model->HICUMflsh == 2)) && (model->HICUMrthGiven) && (model->HICUMrth > 0.0));
int nqs = ( (model->HICUMflnqs != 0 || model->HICUMflcomp < 2.3) && (model->HICUMalit > 0 || model->HICUMalqf > 0));
/* loop through all the instances of the model */
for (here = HICUMinstances(model); here != NULL ;
here=HICUMnextInstance(here)) {
CKTnode *tmpNode;
IFuid tmpName;
if(!here->HICUMareaGiven) {
here->HICUMarea = 1.0;
}
if(!here->HICUMmGiven) {
here->HICUMm = 1.0;
}
if(!here->HICUMdtempGiven) {
here->HICUMdtemp = 0.0;
}
// Warning:
// The scaling with HICUMm and HICUMarea is done here from model to here variables in order to save memory.
// Classical spice scaling with "area" is implemented, but it is not recommended to be used. If you want
// scaling, more sophisticated expressions should be used. Those can be found in modern PDKs or should be
// provided by modeling engineers.
// For discrete devices, the multiplication factor "m" should give reasonable results.
//
// The HICUMm device multiplicaton factor can be exected to give good results.
// The following variables need scaling in HICUM:
// IT : qp0 ~ (area m)**2 qp0 ~ area m icbar ~ area m
// BE junction: cjei0 ~ area m cjep0 ~ m
// ibeis ~ area m ibeps ~ m
// cbepar ~ m -> area scaling not reasonable
// BC junction: cjci0 ~ area m cjcx0 ~ m
// ibcis ~ area m ibcxs ~ m
// ireis ~ area m ireps ~ m
// cbcpar ~ m -> area scaling not reasonable
// qavl ~ area m
// re ~1/(area*m)
// rci0 ~1/(area*m)
// rbx ~1/(area*m) -> assume that scaling with "area" is due to lE0 increase
// rcx ~1/(area*m) -> assume that scaling with "area" is due to lE0 increase
// rbi0 ~1/(area*m) -> assume that scaling with "area" is due to lE0 increase
// rth ~1/(area*m) -> bad assumption, but more transistor geometry needs to be known for accurate scaling
// cth ~ area*m -> bad assumption, but more transistor geometry needs to be known for accurate scaling
// Substrate related parameters not scaled on purpose. This is very geometry dependent?
double area_times_m = here->HICUMm*here->HICUMarea;
//IT
here->HICUMqp0_scaled = model->HICUMqp0 * area_times_m;
here->HICUMc10_scaled = model->HICUMc10 * area_times_m*area_times_m;
here->HICUMicbar_scaled = model->HICUMicbar * area_times_m;
here->HICUMrth_scaled = model->HICUMrth / area_times_m; //very poor assumption
here->HICUMcth_scaled = model->HICUMcth * area_times_m; //very poor assumption
//BE junction
here->HICUMcjei0_scaled = model->HICUMcjei0 * area_times_m;
here->HICUMibeis_scaled = model->HICUMibeis * area_times_m;
here->HICUMireis_scaled = model->HICUMireis * area_times_m;
here->HICUMibeps_scaled = model->HICUMibeps * here->HICUMm;
here->HICUMireps_scaled = model->HICUMireps * here->HICUMm;
here->HICUMcjep0_scaled = model->HICUMcjep0 * here->HICUMm;
here->HICUMcbepar_scaled = model->HICUMcbepar * here->HICUMm;
here->HICUMibets_scaled = model->HICUMibets * area_times_m;
//BC junction
here->HICUMibcis_scaled = model->HICUMibcis * area_times_m;
here->HICUMcjci0_scaled = model->HICUMcjci0 * area_times_m;
here->HICUMcjcx0_scaled = model->HICUMcjcx0 * here->HICUMm;
here->HICUMcbcpar_scaled = model->HICUMcbcpar * here->HICUMm;
here->HICUMibcxs_scaled = model->HICUMibcxs * here->HICUMm;
here->HICUMqavl_scaled = model->HICUMqavl * area_times_m;
//resistances
here->HICUMre_scaled = model->HICUMre / area_times_m;
here->HICUMrci0_scaled = model->HICUMrci0 / area_times_m;
here->HICUMrbx_scaled = model->HICUMrbx / area_times_m;
here->HICUMrcx_scaled = model->HICUMrcx / area_times_m;
here->HICUMrbi0_scaled = model->HICUMrbi0 / area_times_m;
//noise
here->HICUMkf_scaled = model->HICUMkf * pow(here->HICUMm, (1-model->HICUMaf));
here->HICUMkfre_scaled = model->HICUMkfre * pow(here->HICUMm, (1-model->HICUMafre));
here->HICUMstate = *states;
*states += HICUMnumStates;
if(model->HICUMrcx == 0) {
here->HICUMcollCINode = here->HICUMcollNode;
} else if(here->HICUMcollCINode == 0) {
error = CKTmkVolt(ckt,&tmp,here->HICUMname,"collCI");
if(error) return(error);
here->HICUMcollCINode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
}
}
}
}
if(model->HICUMrbx == 0) {
here->HICUMbaseBPNode = here->HICUMbaseNode;
} else if(here->HICUMbaseBPNode == 0){
error = CKTmkVolt(ckt,&tmp,here->HICUMname, "baseBP");
if(error) return(error);
here->HICUMbaseBPNode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,2,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
}
}
}
}
if(model->HICUMre == 0) {
here->HICUMemitEINode = here->HICUMemitNode;
} else if(here->HICUMemitEINode == 0) {
error = CKTmkVolt(ckt,&tmp,here->HICUMname, "emitEI");
if(error) return(error);
here->HICUMemitEINode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,3,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
}
}
}
}
if(model->HICUMrsu == 0) {
here->HICUMsubsSINode = here->HICUMsubsNode;
} else if(here->HICUMsubsSINode == 0) {
error = CKTmkVolt(ckt,&tmp,here->HICUMname, "subsSI");
if(error) return(error);
here->HICUMsubsSINode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,4,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
}
}
}
}
if(model->HICUMrbi0 == 0) {
here->HICUMbaseBINode = here->HICUMbaseBPNode;
} else if(here->HICUMbaseBINode == 0) {
error = CKTmkVolt(ckt, &tmp, here->HICUMname, "baseBI");
if(error) return(error);
here->HICUMbaseBINode = tmp->number;
if (ckt->CKTcopyNodesets) {
if (CKTinst2Node(ckt,here,5,&tmpNode,&tmpName)==OK) {
if (tmpNode->nsGiven) {
tmp->nodeset=tmpNode->nodeset;
tmp->nsGiven=tmpNode->nsGiven;
}
}
}
}
if (selfheat) {
if (here->HICUMtempNode == 0) { // no external node for temperature
error = CKTmkVolt(ckt,&tmp,here->HICUMname,"dT"); // create internal node
if (error) return(error);
here->HICUMtempNode = tmp->number;
}
} else {
if (here->HICUMtempNode > 0) { // external temp node is given, but no she parameter
here->HICUMtempNode = 0;
}
}
if (nqs) {
if(here->HICUMxfNode == 0) {
error = CKTmkVolt(ckt, &tmp, here->HICUMname, "xf");
if(error) return(error);
here->HICUMxfNode = tmp->number;
}
if(here->HICUMxf1Node == 0) {
error = CKTmkVolt(ckt, &tmp, here->HICUMname, "xf1");
if(error) return(error);
here->HICUMxf1Node = tmp->number;
}
if(here->HICUMxf2Node == 0) {
error = CKTmkVolt(ckt, &tmp, here->HICUMname, "xf2");
if(error) return(error);
here->HICUMxf2Node = tmp->number;
}
} else {
here->HICUMxfNode = 0;
here->HICUMxf1Node = 0;
here->HICUMxf2Node = 0;
}
/* macro to make elements with built in test for out of memory */
#define TSTALLOC(ptr,first,second) \
do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
return(E_NOMEM);\
} } while(0)
TSTALLOC(HICUMcollCollPtr,HICUMcollNode,HICUMcollNode);
TSTALLOC(HICUMbaseBasePtr,HICUMbaseNode,HICUMbaseNode);
TSTALLOC(HICUMemitEmitPtr,HICUMemitNode,HICUMemitNode);
TSTALLOC(HICUMsubsSubsPtr,HICUMsubsNode,HICUMsubsNode);
TSTALLOC(HICUMcollCICollCIPtr,HICUMcollCINode,HICUMcollCINode);
TSTALLOC(HICUMbaseBIBaseBIPtr,HICUMbaseBINode,HICUMbaseBINode);
TSTALLOC(HICUMemitEIEmitEIPtr,HICUMemitEINode,HICUMemitEINode);
TSTALLOC(HICUMbaseBPBaseBPPtr,HICUMbaseBPNode,HICUMbaseBPNode);
TSTALLOC(HICUMsubsSISubsSIPtr,HICUMsubsSINode,HICUMsubsSINode);
TSTALLOC(HICUMbaseEmitPtr,HICUMbaseNode,HICUMemitNode); //b-e
TSTALLOC(HICUMemitBasePtr,HICUMemitNode,HICUMbaseNode); //e-b
TSTALLOC(HICUMbaseBaseBPPtr,HICUMbaseNode,HICUMbaseBPNode); //b-bp
TSTALLOC(HICUMbaseBPBasePtr,HICUMbaseBPNode,HICUMbaseNode); //bp-b
TSTALLOC(HICUMemitEmitEIPtr,HICUMemitNode,HICUMemitEINode); //e-ei
TSTALLOC(HICUMemitEIEmitPtr,HICUMemitEINode,HICUMemitNode); //ei-e
TSTALLOC(HICUMsubsSubsSIPtr,HICUMsubsNode,HICUMsubsSINode); //s-si
TSTALLOC(HICUMsubsSISubsPtr,HICUMsubsSINode,HICUMsubsNode); //si-s
TSTALLOC(HICUMcollCIBasePtr,HICUMcollCINode,HICUMbaseNode); //b-ci
TSTALLOC(HICUMbaseCollCIPtr,HICUMbaseNode,HICUMcollCINode); //ci-b
TSTALLOC(HICUMcollCIEmitEIPtr,HICUMcollCINode,HICUMemitEINode); //ci-ei
TSTALLOC(HICUMemitEICollCIPtr,HICUMemitEINode,HICUMcollCINode); //ei-ci
TSTALLOC(HICUMbaseBPBaseBIPtr,HICUMbaseBPNode,HICUMbaseBINode); //bp-bi
TSTALLOC(HICUMbaseBIBaseBPPtr,HICUMbaseBINode,HICUMbaseBPNode); //bi-bp
TSTALLOC(HICUMbaseBPEmitEIPtr,HICUMbaseBPNode,HICUMemitEINode); //bp-ei
TSTALLOC(HICUMemitEIBaseBPPtr,HICUMemitEINode,HICUMbaseBPNode); //ei-bp
TSTALLOC(HICUMbaseBPEmitPtr,HICUMbaseBPNode,HICUMemitNode); //bp-e
TSTALLOC(HICUMemitBaseBPPtr,HICUMemitNode,HICUMbaseBPNode); //e-bp
TSTALLOC(HICUMbaseBPSubsSIPtr,HICUMbaseBPNode,HICUMsubsSINode); //bp-si
TSTALLOC(HICUMsubsSIBaseBPPtr,HICUMsubsSINode,HICUMbaseBPNode); //si-bp
TSTALLOC(HICUMbaseBIEmitEIPtr,HICUMbaseBINode,HICUMemitEINode); //ei-bi
TSTALLOC(HICUMemitEIBaseBIPtr,HICUMemitEINode,HICUMbaseBINode); //bi-ei
if (nqs) {
TSTALLOC(HICUMbaseBIXfPtr ,HICUMbaseBINode,HICUMxfNode); //bi - xf
TSTALLOC(HICUMemitEIXfPtr ,HICUMemitEINode,HICUMxfNode); //ei - xf
}
TSTALLOC(HICUMbaseBICollCIPtr,HICUMbaseBINode,HICUMcollCINode); //ci-bi
TSTALLOC(HICUMcollCIBaseBIPtr,HICUMcollCINode,HICUMbaseBINode); //bi-ci
TSTALLOC(HICUMbaseBPCollCIPtr,HICUMbaseBPNode,HICUMcollCINode); //bp-ci
TSTALLOC(HICUMcollCIBaseBPPtr,HICUMcollCINode,HICUMbaseBPNode); //ci-bp
TSTALLOC(HICUMsubsSICollCIPtr,HICUMsubsSINode,HICUMcollCINode); //si-ci
TSTALLOC(HICUMcollCISubsSIPtr,HICUMcollCINode,HICUMsubsSINode); //ci-si
TSTALLOC(HICUMcollCICollPtr,HICUMcollCINode,HICUMcollNode); //ci-c
TSTALLOC(HICUMcollCollCIPtr,HICUMcollNode,HICUMcollCINode); //c-ci
TSTALLOC(HICUMsubsCollPtr,HICUMsubsNode,HICUMcollNode); //s-c
TSTALLOC(HICUMcollSubsPtr,HICUMcollNode,HICUMsubsNode); //c-s
if (nqs) {
TSTALLOC(HICUMxf1Xf1Ptr ,HICUMxf1Node ,HICUMxf1Node);
TSTALLOC(HICUMxf1BaseBIPtr,HICUMxf1Node ,HICUMbaseBINode);
TSTALLOC(HICUMxf1EmitEIPtr,HICUMxf1Node ,HICUMemitEINode);
TSTALLOC(HICUMxf1CollCIPtr,HICUMxf1Node ,HICUMcollCINode);
TSTALLOC(HICUMxf1Xf2Ptr ,HICUMxf1Node ,HICUMxf2Node);
TSTALLOC(HICUMxf2Xf1Ptr ,HICUMxf2Node ,HICUMxf1Node);
TSTALLOC(HICUMxf2BaseBIPtr,HICUMxf2Node ,HICUMbaseBINode);
TSTALLOC(HICUMxf2EmitEIPtr,HICUMxf2Node ,HICUMemitEINode);
TSTALLOC(HICUMxf2CollCIPtr,HICUMxf2Node ,HICUMcollCINode);
TSTALLOC(HICUMxf2Xf2Ptr ,HICUMxf2Node ,HICUMxf2Node);
TSTALLOC(HICUMemitEIXf2Ptr,HICUMemitEINode,HICUMxf2Node);
TSTALLOC(HICUMcollCIXf2Ptr,HICUMcollCINode,HICUMxf2Node);
TSTALLOC(HICUMxfXfPtr ,HICUMxfNode,HICUMxfNode);
TSTALLOC(HICUMxfEmitEIPtr ,HICUMxfNode,HICUMemitEINode);
TSTALLOC(HICUMxfCollCIPtr ,HICUMxfNode,HICUMcollCINode);
TSTALLOC(HICUMxfBaseBIPtr ,HICUMxfNode,HICUMbaseBINode);
}
TSTALLOC(HICUMbaseBPSubsSIPtr ,HICUMbaseBPNode,HICUMsubsSINode);
TSTALLOC(HICUMsubsSIBaseBPPtr ,HICUMsubsSINode,HICUMbaseBPNode);
if (selfheat) {
TSTALLOC(HICUMcollTempPtr, HICUMcollNode, HICUMtempNode);
TSTALLOC(HICUMbaseTempPtr,HICUMbaseNode,HICUMtempNode);
TSTALLOC(HICUMemitTempPtr,HICUMemitNode,HICUMtempNode);
TSTALLOC(HICUMcollCItempPtr,HICUMcollCINode,HICUMtempNode);
TSTALLOC(HICUMbaseBItempPtr,HICUMbaseBINode,HICUMtempNode);
TSTALLOC(HICUMbaseBPtempPtr,HICUMbaseBPNode,HICUMtempNode);
TSTALLOC(HICUMemitEItempPtr,HICUMemitEINode,HICUMtempNode);
TSTALLOC(HICUMsubsSItempPtr,HICUMsubsSINode,HICUMtempNode);
TSTALLOC(HICUMsubsTempPtr ,HICUMsubsNode ,HICUMtempNode);
TSTALLOC(HICUMcollTempPtr ,HICUMcollNode ,HICUMtempNode);
TSTALLOC(HICUMtempCollPtr,HICUMtempNode,HICUMcollNode);
TSTALLOC(HICUMtempBasePtr,HICUMtempNode,HICUMbaseNode);
TSTALLOC(HICUMtempEmitPtr,HICUMtempNode,HICUMemitNode);
TSTALLOC(HICUMtempCollCIPtr,HICUMtempNode,HICUMcollCINode);
TSTALLOC(HICUMtempBaseBIPtr,HICUMtempNode,HICUMbaseBINode);
TSTALLOC(HICUMtempBaseBPPtr,HICUMtempNode,HICUMbaseBPNode);
TSTALLOC(HICUMtempEmitEIPtr,HICUMtempNode,HICUMemitEINode);
TSTALLOC(HICUMtempSubsSIPtr,HICUMtempNode,HICUMsubsSINode);
TSTALLOC(HICUMtempTempPtr,HICUMtempNode,HICUMtempNode);
if (nqs) {
TSTALLOC(HICUMxfTempPtr ,HICUMxfNode,HICUMtempNode);
TSTALLOC(HICUMxf2TempPtr ,HICUMxf2Node ,HICUMtempNode);
TSTALLOC(HICUMxf1TempPtr ,HICUMxf1Node ,HICUMtempNode);
}
}
}
}
return(OK);
}
int
HICUMunsetup(
GENmodel *inModel,
CKTcircuit *ckt)
{
HICUMmodel *model;
HICUMinstance *here;
for (model = (HICUMmodel *)inModel; model != NULL;
model = HICUMnextModel(model))
{
int selfheat = (((model->HICUMflsh == 1) || (model->HICUMflsh == 2)) && (model->HICUMrthGiven) && (model->HICUMrth > 0.0));
int nqs = ( (model->HICUMflnqs != 0 || model->HICUMflcomp < 2.3) && (model->HICUMalit > 0 || model->HICUMalqf > 0));
for (here = HICUMinstances(model); here != NULL;
here=HICUMnextInstance(here))
{
if (here->HICUMcollCINode > 0
&& here->HICUMcollCINode != here->HICUMcollNode)
CKTdltNNum(ckt, here->HICUMcollCINode);
here->HICUMcollCINode = 0;
if (here->HICUMbaseBINode > 0
&& here->HICUMbaseBPNode != here->HICUMbaseBINode)
CKTdltNNum(ckt, here->HICUMbaseBINode);
here->HICUMbaseBINode = 0;
if (here->HICUMbaseBPNode > 0
&& here->HICUMbaseBPNode != here->HICUMbaseNode)
CKTdltNNum(ckt, here->HICUMbaseBPNode);
here->HICUMbaseBPNode = 0;
if (here->HICUMemitEINode > 0
&& here->HICUMemitEINode != here->HICUMemitNode)
CKTdltNNum(ckt, here->HICUMemitEINode);
here->HICUMemitEINode = 0;
if (here->HICUMsubsSINode > 0
&& here->HICUMsubsSINode != here->HICUMsubsNode)
CKTdltNNum(ckt, here->HICUMsubsSINode);
here->HICUMsubsSINode = 0;
if (selfheat) {
if (here->HICUMtempNode > 6) { // it is an internal node
CKTdltNNum(ckt, here->HICUMtempNode);
here->HICUMtempNode = 0;
}
}
if (nqs) {
if(here->HICUMxfNode > 0)
CKTdltNNum(ckt, here->HICUMxfNode);
here->HICUMxfNode = 0;
if(here->HICUMxf1Node > 0)
CKTdltNNum(ckt, here->HICUMxf1Node);
here->HICUMxf1Node = 0;
if(here->HICUMxf2Node > 0)
CKTdltNNum(ckt, here->HICUMxf2Node);
here->HICUMxf2Node = 0;
}
}
}
return OK;
}

73
src/spicelib/devices/hicum2/hicum2soachk.c

@ -0,0 +1,73 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/trandefs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
#include "ngspice/cpdefs.h"
int
HICUMsoaCheck(CKTcircuit *ckt, GENmodel *inModel)
{
HICUMmodel *model = (HICUMmodel *) inModel;
HICUMinstance *here;
double vbe, vbc, vce; /* actual bjt voltages */
int maxwarns;
static int warns_vbe = 0, warns_vbc = 0, warns_vce = 0;
if (!ckt) {
warns_vbe = 0;
warns_vbc = 0;
warns_vce = 0;
return OK;
}
maxwarns = ckt->CKTsoaMaxWarns;
for (; model; model = HICUMnextModel(model)) {
for (here = HICUMinstances(model); here; here=HICUMnextInstance(here)) {
vbe = fabs(ckt->CKTrhsOld [here->HICUMbaseNode] -
ckt->CKTrhsOld [here->HICUMemitNode]);
vbc = fabs(ckt->CKTrhsOld [here->HICUMbaseNode] -
ckt->CKTrhsOld [here->HICUMcollNode]);
vce = fabs(ckt->CKTrhsOld [here->HICUMcollNode] -
ckt->CKTrhsOld [here->HICUMemitNode]);
if (vbe > model->HICUMvbeMax)
if (warns_vbe < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"|Vbe|=%g has exceeded Vbe_max=%g\n",
vbe, model->HICUMvbeMax);
warns_vbe++;
}
if (vbc > model->HICUMvbcMax)
if (warns_vbc < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"|Vbc|=%g has exceeded Vbc_max=%g\n",
vbc, model->HICUMvbcMax);
warns_vbc++;
}
if (vce > model->HICUMvceMax)
if (warns_vce < maxwarns) {
soa_printf(ckt, (GENinstance*) here,
"|Vce|=%g has exceeded Vce_max=%g\n",
vce, model->HICUMvceMax);
warns_vce++;
}
}
}
return OK;
}

43
src/spicelib/devices/hicum2/hicum2trunc.c

@ -0,0 +1,43 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
/*
* This routine performs truncation error calculations for
* HICUMs in the circuit.
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "hicum2defs.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
HICUMtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
{
HICUMmodel *model = (HICUMmodel*)inModel;
HICUMinstance *here;
for( ; model != NULL; model = HICUMnextModel(model)) {
for(here=HICUMinstances(model);here!=NULL;
here = HICUMnextInstance(here)){
CKTterr(here->HICUMqrbi, ckt, timeStep);
CKTterr(here->HICUMqjei, ckt, timeStep);
CKTterr(here->HICUMqf, ckt, timeStep);
CKTterr(here->HICUMqjci, ckt, timeStep);
CKTterr(here->HICUMqr, ckt, timeStep);
CKTterr(here->HICUMqjep, ckt, timeStep);
CKTterr(here->HICUMqjcx0_i, ckt, timeStep);
CKTterr(here->HICUMqjcx0_ii, ckt, timeStep);
CKTterr(here->HICUMqdsu, ckt, timeStep);
CKTterr(here->HICUMqjs, ckt, timeStep);
CKTterr(here->HICUMqscp, ckt, timeStep);
}
}
return(OK);
}

3350
src/spicelib/devices/hicum2/hicumL2.cpp
File diff suppressed because it is too large
View File

23
src/spicelib/devices/hicum2/hicumL2.hpp

@ -0,0 +1,23 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#ifndef hicumL2_H
#define hicumL2_H
#include "hicum2defs.h"
#ifdef __cplusplus
extern "C" {
#endif
void hicum_diode(double T, double IS, double UM1, double U, double *Iz, double *Gz, double *Tz);
void hicum_qjmodf(double T, double c_0, double u_d, double z, double a_j, double U_cap, double *C, double *C_dU, double *C_dvt, double *Qz, double *Qz_dU, double *Qz_dvt);
static double HICUMlimitlog( double deltemp, double deltemp_old, double LIM_TOL, int *check);
int hicum_thermal_update(HICUMmodel *, HICUMinstance *, double * Temp, double * Tdev_Vrth);
int HICUMload(GENmodel *inModel, CKTcircuit *ckt);
int HICUMtemp(GENmodel *inModel, CKTcircuit *ckt);
#ifdef __cplusplus
}
#endif
#endif /* hicumL2_H */

521
src/spicelib/devices/hicum2/hicumL2temp.cpp

@ -0,0 +1,521 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#include "cmath"
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
#include <duals/dual>
#include "hicumL2.hpp"
#include <functional>
//ngspice header files written in C
#ifdef __cplusplus
extern "C"
{
#endif
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/smpdefs.h"
#include "hicum2defs.h"
#include "ngspice/const.h"
#include "ngspice/sperror.h"
#include "ngspice/ifsim.h"
#include "ngspice/suffix.h"
#ifdef __cplusplus
}
#endif
using namespace duals::literals;
#define TMAX 326.85
#define TMIN -100.0
#define LN_EXP_LIMIT 11.0
duals::duald clip_temperature(duals::duald T){
// smooth clipping function for device temperature, if self heating increases temperature beyond
// T0+TMAX or below T0-TMIN
duals::duald Tdev;
Tdev = T;
if (T<(TMIN+CONSTCtoK+1.0)){
Tdev = TMIN+CONSTCtoK+exp(T-TMIN+CONSTCtoK-1.0);
} else if (T>(TMAX+CONSTCtoK-1.0)) {
Tdev = TMAX+CONSTCtoK-exp(TMAX+CONSTCtoK-T-1.0);
};
return Tdev;
};
void TMPHICJ(double , double , double , double , double ,
double , double , double , double , double , double ,
double *, double *, double *);
// TEMPERATURE UPDATE OF JUNCTION CAPACITANCE RELATED PARAMETERS
// INPUT:
// mostly model parameters
// x : zero bias junction capacitance
// y : junction built-in potential
// z : grading co-efficient
// w : ratio of maximum to zero-bias value of capacitance or punch-through voltage
// is_al : condition factor to check what "w" stands for
// vgeff : band-gap voltage
// IMPLICIT INPUT:
// vt : thermal voltage
// vt0,qtt0,ln_qtt0,mg : other model variables
// OUTPUT:
// c_j_t : temperature update of "c_j"
// vd_t : temperature update of "vd0"
// w_t : temperature update of "w"
void TMPHICJ(duals::duald vt, double vt0, duals::duald qtt0, duals::duald ln_qtt0, double mg,
double c_j, double vd0, double z, double w, double is_al, double vgeff,
duals::duald *c_j_t, duals::duald *vd_t, duals::duald *w_t)
{
duals::duald vdj0,vdjt,vdt;
if (c_j > 0.0) {
vdj0 = 2*vt0*log(exp(vd0*0.5/vt0)-exp(-0.5*vd0/vt0));
vdjt = vdj0*qtt0+vgeff*(1-qtt0)-mg*vt*ln_qtt0;
vdt = vdjt+2*vt*log(0.5*(1+sqrt(1+4*exp(-vdjt/vt))));
*vd_t = vdt;
*c_j_t = c_j*exp(z*log(vd0/(*vd_t)));
if (is_al == 1) {
*w_t = w*(*vd_t)/vd0;
} else {
*w_t = w;
}
} else {
*c_j_t = c_j;
*vd_t = vd0;
*w_t = w;
}
}
void hicum_TMPHICJ(duals::duald vt, double vt0, duals::duald qtt0, duals::duald ln_qtt0, double mg,
double c_j, double vd0, double z, double w, double is_al, double vgeff,
double *c_j_t, double *vd_t, double *w_t,
double *c_j_t_dT, double *vd_t_dT, double *w_t_dT)
{
duals::duald c_j_t_result = 0;
duals::duald vd_t_result = 0;
duals::duald w_t_result = 0;
TMPHICJ(vt, vt0, qtt0, ln_qtt0, mg, c_j, vd0, z, w, is_al, vgeff, &c_j_t_result, &vd_t_result, &w_t_result);
*c_j_t = c_j_t_result.rpart();
*c_j_t_dT = c_j_t_result.dpart();
*vd_t = vd_t_result.rpart();
*vd_t_dT = vd_t_result.dpart();
*w_t = w_t_result.rpart();
*w_t_dT = w_t_result.dpart();
}
int
HICUMtemp(GENmodel *inModel, CKTcircuit *ckt)
/* Pre-compute many useful parameters
*/
{
int iret;
HICUMmodel *model = (HICUMmodel *)inModel;
HICUMinstance *here;
/* loop through all the bipolar models */
for( ; model != NULL; model = HICUMnextModel(model)) {
/* loop through all the instances of the model */
for (here = HICUMinstances(model); here != NULL ;
here=HICUMnextInstance(here)) {
if(!here->HICUMtempGiven) here->HICUMtemp = ckt->CKTtemp;
if(here->HICUMdtempGiven) here->HICUMtemp = here->HICUMtemp + here->HICUMdtemp;
iret = hicum_thermal_update(model, here, &here -> HICUMtemp, &here->HICUMtemp_Vrth);
}
}
return(OK);
}
int hicum_thermal_update(HICUMmodel *inModel, HICUMinstance *inInstance, double * HICUMTemp, double * Tdev_Vrth)
{
HICUMmodel *model = (HICUMmodel *)inModel;
HICUMinstance *here = (HICUMinstance *)inInstance;
double mg,k10,k20,avs,vgb_t0,vge_t0,vgbe_t0,vgbe0,vgbc0,vgsc0;
double zetabci,zetabcxt,zetasct;
duals::duald temp, dT, vt, qtt0, ln_qtt0;
duals::duald k1,k2,dvg0,vge_t,vgb_t,vgbe_t,cratio_t,a;
double cratio_t_real, cratio_t_dual;
double Tnom, zetatef, cjcx01, cjcx02, C_1;
duals::duald cjei0_t, vdei_t, cjep0_t, vdep_t;
Tnom = model->HICUMtnom;
k10 = model->HICUMf1vg*Tnom*log(Tnom);
k20 = model->HICUMf2vg*Tnom;
avs = model->HICUMalvs*Tnom;
vgb_t0 = model->HICUMvgb+k10+k20;
vge_t0 = model->HICUMvge+k10+k20;
vgbe_t0 = (vgb_t0+vge_t0)/2;
vgbe0 = (model->HICUMvgb+model->HICUMvge)/2;
vgbc0 = (model->HICUMvgb+model->HICUMvgc)/2;
vgsc0 = (model->HICUMvgs+model->HICUMvgc)/2;
mg = 3-model->HICUMf1vg/CONSTKoverQ;
zetabci = mg+1-model->HICUMzetaci;
zetabcxt= mg+1-model->HICUMzetacx;
zetasct = mg-1.5;
// Smooth ngspice T clipping
temp = clip_temperature( *(HICUMTemp)+1_e );
*(HICUMTemp) = temp.rpart();
*(Tdev_Vrth) = temp.dpart();
// original HICUM clipping for Tdev => left here for reference
// *(Tdev_Vrth) = 1.0;
// if(*(HICUMTemp) < TMIN + CONSTCtoK) {
// *(HICUMTemp) = TMIN + CONSTCtoK;
// *(Tdev_Vrth) = 0.0;
// } else {
// if (*(HICUMTemp) > TMAX + CONSTCtoK) {
// *(HICUMTemp) = TMAX + CONSTCtoK;
// *(Tdev_Vrth) = 0.0;
// }
//}
//This routine calculates the derivatives with respect to Vrth. Since at some point
// Tdev becomes constant (see above), we need to account for this like below.
//temp = *(HICUMTemp)+1_e* *(Tdev_Vrth); // dual number device temperature
vt = temp*CONSTKoverQ; // dual valued temperature voltage
here->HICUMvt0 = Tnom * CONSTKoverQ;
here->HICUMvt.rpart = vt.rpart();
here->HICUMvt.dpart = vt.dpart();
dT = temp-Tnom;
qtt0 = temp/Tnom;
ln_qtt0 = log(qtt0);
k1 = model->HICUMf1vg*temp*log(temp);
k2 = model->HICUMf2vg*temp;
vgb_t = model->HICUMvgb+k1+k2;
vge_t = model->HICUMvge+k1+k2;
vgbe_t = (vgb_t+vge_t)/2;
here->HICUMtVcrit = here->HICUMvt.rpart *
log(here->HICUMvt.rpart / (CONSTroot2*here->HICUMibeis_scaled));
//Internal b-e junction capacitance
hicum_TMPHICJ(vt, here->HICUMvt0, qtt0, ln_qtt0, mg,
here->HICUMcjei0_scaled, model->HICUMvdei, model->HICUMzei, model->HICUMajei, 1, vgbe0,
&here->HICUMcjei0_t.rpart, &here->HICUMvdei_t.rpart, &here->HICUMajei_t.rpart,
&here->HICUMcjei0_t.dpart, &here->HICUMvdei_t.dpart, &here->HICUMajei_t.dpart);
cjei0_t.rpart(here->HICUMcjei0_t.rpart);
cjei0_t.dpart(here->HICUMcjei0_t.dpart);
vdei_t.rpart(here->HICUMvdei_t.rpart);
vdei_t.dpart(here->HICUMvdei_t.dpart);
if (model->HICUMflcomp < 2.3) {
duals::duald V_gT, r_VgVT, k;
V_gT = 3.0*vt*ln_qtt0 + model->HICUMvgb*(qtt0-1.0);
r_VgVT = V_gT/vt;
//Internal b-e diode saturation currents
a = model->HICUMmcf*r_VgVT/model->HICUMmbei - model->HICUMalb*dT;
a = here->HICUMibeis_scaled*exp(a);
here->HICUMibeis_t.rpart = a.rpart();
here->HICUMibeis_t.dpart = a.dpart();
a = model->HICUMmcf*r_VgVT/model->HICUMmrei - model->HICUMalb*dT;
a = here->HICUMireis_scaled*exp(a);
here->HICUMireis_t.rpart = a.rpart();
here->HICUMireis_t.dpart = a.dpart();
//Peripheral b-e diode saturation currents
a = model->HICUMmcf*r_VgVT/model->HICUMmbep - model->HICUMalb*dT;
a = here->HICUMibeps_scaled*exp(a);
here->HICUMibeps_t.rpart = a.rpart();
here->HICUMibeps_t.dpart = a.dpart();
a = model->HICUMmcf*r_VgVT/model->HICUMmrep - model->HICUMalb*dT;
a = here->HICUMireps_scaled*exp(a);
here->HICUMireps_t.rpart = a.rpart();
here->HICUMireps_t.dpart = a.dpart();
//Internal b-c diode saturation current
a = r_VgVT/model->HICUMmbci;
a = here->HICUMibcis_scaled*exp(a);
here->HICUMibcis_t.rpart = a.rpart();
here->HICUMibcis_t.dpart = a.dpart();
//External b-c diode saturation currents
a = r_VgVT/model->HICUMmbcx;
a = here->HICUMibcxs_scaled*exp(a);
here->HICUMibcxs_t.rpart = a.rpart();
here->HICUMibcxs_t.dpart = a.dpart();
//Saturation transfer current for substrate transistor
a = r_VgVT/model->HICUMmsf;
a = model->HICUMitss*exp(a);
here->HICUMitss_t.rpart = a.rpart();
here->HICUMitss_t.rpart = a.dpart();
//Saturation current for c-s diode
a = r_VgVT/model->HICUMmsc;
a = model->HICUMiscs*exp(a);
here->HICUMiscs_t.rpart = a.rpart();
here->HICUMiscs_t.dpart = a.dpart();
//Zero bias hole charge
a = vdei_t/model->HICUMvdei;
a = here->HICUMqp0_scaled*(1.0+0.5*model->HICUMzei*(1.0-a));
here->HICUMqp0_t.rpart = a.rpart();
here->HICUMqp0_t.dpart = a.dpart();
//Voltage separating ohmic and saturation velocity regime
a = model->HICUMvlim*(1.0-model->HICUMalvs*dT)*exp(model->HICUMzetaci*ln_qtt0);
k = (a-vt)/vt;
if (k.rpart() < LN_EXP_LIMIT) {
a = vt + vt*log(1.0+exp(k));
}
here->HICUMvlim_t.rpart = a.rpart();
here->HICUMvlim_t.dpart = a.dpart();
//Neutral emitter storage time
a = 1.0+model->HICUMalb*dT;
k = 0.5*(a+sqrt(a*a+0.01));
a = model->HICUMtef0*qtt0/k;
here->HICUMtef0_t.rpart = a.rpart();
here->HICUMtef0_t.dpart = a.dpart();
} else {
//Internal b-e diode saturation currents
a = here->HICUMibeis_scaled*exp(model->HICUMzetabet*ln_qtt0+model->HICUMvge/vt*(qtt0-1));
here->HICUMibeis_t.rpart = a.rpart();
here->HICUMibeis_t.dpart = a.dpart();
if (model->HICUMflcomp>=2.3) {
a = here->HICUMireis_scaled*exp(mg/model->HICUMmrei*ln_qtt0+vgbe0/(model->HICUMmrei*vt)*(qtt0-1));
} else {
a = here->HICUMireis_scaled*exp(0.5*mg*ln_qtt0+0.5*vgbe0/vt*(qtt0-1));
}
here->HICUMireis_t.rpart = a.rpart();
here->HICUMireis_t.dpart = a.dpart();
//Peripheral b-e diode saturation currents
a = here->HICUMibeps_scaled*exp(model->HICUMzetabet*ln_qtt0+model->HICUMvge/vt*(qtt0-1));
here->HICUMibeps_t.rpart = a.rpart();
here->HICUMibeps_t.dpart = a.dpart();
if (model->HICUMflcomp>=2.3) {
a = here->HICUMireps_scaled*exp(mg/model->HICUMmrep*ln_qtt0+vgbe0/(model->HICUMmrep*vt)*(qtt0-1));
} else {
a = here->HICUMireps_scaled*exp(0.5*mg*qtt0+0.5*vgbe0/vt*(qtt0-1));
}
here->HICUMireps_t.rpart = a.rpart();
here->HICUMireps_t.dpart = a.dpart();
//Internal b-c diode saturation currents
a = here->HICUMibcis_scaled*exp(zetabci*ln_qtt0+model->HICUMvgc/vt*(qtt0-1));
here->HICUMibcis_t.rpart = a.rpart();
here->HICUMibcis_t.dpart = a.dpart();
//External b-c diode saturation currents
a = here->HICUMibcxs_scaled*exp(zetabcxt*ln_qtt0+model->HICUMvgc/vt*(qtt0-1));
here->HICUMibcxs_t.rpart = a.rpart();
here->HICUMibcxs_t.dpart = a.dpart();
//Saturation transfer current for substrate transistor
a = model->HICUMitss*exp(zetasct*ln_qtt0+model->HICUMvgc/vt*(qtt0-1));
here->HICUMitss_t.rpart = a.rpart();
here->HICUMitss_t.dpart = a.dpart();
//Saturation current for c-s diode
a = model->HICUMiscs*exp(zetasct*ln_qtt0+model->HICUMvgs/vt*(qtt0-1));
here->HICUMiscs_t.rpart = a.rpart();
here->HICUMiscs_t.dpart = a.dpart();
//Zero bias hole charge
a = exp(model->HICUMzei*log(vdei_t/model->HICUMvdei));
a = here->HICUMqp0_scaled*(2.0-a);
here->HICUMqp0_t.rpart = a.rpart();
here->HICUMqp0_t.dpart = a.dpart();
//Voltage separating ohmic and saturation velocity regime
a = model->HICUMvlim*exp((model->HICUMzetaci-avs)*ln_qtt0);
here->HICUMvlim_t.rpart = a.rpart();
here->HICUMvlim_t.dpart = a.dpart();
//Neutral emitter storage time
if (model->HICUMflcomp >= 2.3) {
a = model->HICUMtef0;
} else {
zetatef = model->HICUMzetabet-model->HICUMzetact-0.5;
dvg0 = model->HICUMvgb-model->HICUMvge;
a = model->HICUMtef0*exp(zetatef*ln_qtt0-dvg0/vt*(qtt0-1));
}
here->HICUMtef0_t.rpart = a.rpart();
here->HICUMtef0_t.dpart = a.dpart();
}
//GICCR prefactor
a = here->HICUMc10_scaled*exp(model->HICUMzetact*ln_qtt0+model->HICUMvgb/vt*(qtt0-1));
here->HICUMc10_t.rpart = a.rpart();
here->HICUMc10_t.dpart = a.dpart();
// Low-field internal collector resistance
a = here->HICUMrci0_scaled*exp(model->HICUMzetaci*ln_qtt0);
here->HICUMrci0_t.rpart = a.rpart();
here->HICUMrci0_t.dpart = a.dpart();
//Internal c-e saturation voltage
a = model->HICUMvces*(1+model->HICUMalces*dT);
here->HICUMvces_t.rpart = a.rpart();
here->HICUMvces_t.dpart = a.dpart();
//Internal b-c junction capacitance
hicum_TMPHICJ(vt, here->HICUMvt0, qtt0, ln_qtt0, mg,
here->HICUMcjci0_scaled, model->HICUMvdci, model->HICUMzci, model->HICUMvptci, 0, vgbc0,
&here->HICUMcjci0_t.rpart, &here->HICUMvdci_t.rpart, &here->HICUMvptci_t.rpart,
&here->HICUMcjci0_t.dpart, &here->HICUMvdci_t.dpart, &here->HICUMvptci_t.dpart);
//Low-current forward transit time
a = model->HICUMt0*(1+model->HICUMalt0*dT+model->HICUMkt0*dT*dT);
here->HICUMt0_t.rpart = a.rpart();
here->HICUMt0_t.dpart = a.dpart();
//Saturation time constant at high current densities
a = model->HICUMthcs*exp((model->HICUMzetaci-1)*ln_qtt0);
here->HICUMthcs_t.rpart = a.rpart();
here->HICUMthcs_t.dpart = a.dpart();
//Avalanche current factors
a = model->HICUMfavl*exp(model->HICUMalfav*dT);
here->HICUMfavl_t.rpart = a.rpart();
here->HICUMfavl_t.dpart = a.dpart();
a = here->HICUMqavl_scaled*exp(model->HICUMalqav*dT);
here->HICUMqavl_t.rpart = a.rpart();
here->HICUMqavl_t.dpart = a.dpart();
a = model->HICUMkavl*exp(model->HICUMalkav*dT);
here->HICUMkavl_t.rpart = a.rpart();
here->HICUMkavl_t.dpart = a.dpart();
//Zero bias internal base resistance
a = here->HICUMrbi0_scaled*exp(model->HICUMzetarbi*ln_qtt0);
here->HICUMrbi0_t.rpart = a.rpart();
here->HICUMrbi0_t.dpart = a.dpart();
//Peripheral b-e junction capacitance
hicum_TMPHICJ(vt, here->HICUMvt0, qtt0, ln_qtt0, mg,
here->HICUMcjep0_scaled, model->HICUMvdep, model->HICUMzep, model->HICUMajep, 1, vgbe0,
&here->HICUMcjep0_t.rpart, &here->HICUMvdep_t.rpart, &here->HICUMajep_t.rpart,
&here->HICUMcjep0_t.dpart, &here->HICUMvdep_t.dpart, &here->HICUMajep_t.dpart);
cjep0_t.rpart(here->HICUMcjep0_t.rpart);
cjep0_t.dpart(here->HICUMcjep0_t.dpart);
vdep_t.rpart(here->HICUMvdep_t.rpart);
vdep_t.dpart(here->HICUMvdep_t.dpart);
//Tunneling current factors
if (here->HICUMibets_scaled > 0) { // HICTUN_T
duals::duald a_eg,ab,aa;
ab = 1.0;
aa = 1.0;
a_eg = vgbe_t0/vgbe_t;
if(model->HICUMtunode==1 && here->HICUMcjep0_scaled > 0.0 && model->HICUMvdep >0.0) {
ab = (cjep0_t/here->HICUMcjep0_scaled)*sqrt(a_eg)*vdep_t*vdep_t/(model->HICUMvdep*model->HICUMvdep);
aa = (model->HICUMvdep/vdep_t)*(here->HICUMcjep0_scaled/cjep0_t)*pow(a_eg,-1.5);
} else if (model->HICUMtunode==0 && here->HICUMcjei0_scaled > 0.0 && model->HICUMvdei >0.0) {
ab = (cjei0_t/here->HICUMcjei0_scaled)*sqrt(a_eg)*vdei_t*vdei_t/(model->HICUMvdei*model->HICUMvdei);
aa = (model->HICUMvdei/vdei_t)*(here->HICUMcjei0_scaled/cjei0_t)*pow(a_eg,-1.5);
}
a = here->HICUMibets_scaled*ab;
here->HICUMibets_t.rpart = a.rpart();
here->HICUMibets_t.dpart = a.dpart();
a = model->HICUMabet*aa;
here->HICUMabet_t.rpart = a.rpart();
here->HICUMabet_t.dpart = a.dpart();
} else {
here->HICUMibets_t.rpart = 0;
here->HICUMibets_t.dpart = 0;
here->HICUMabet_t.rpart = 1;
here->HICUMabet_t.dpart = 0;
}
//Depletion capacitance splitting at b-c junction
//Capacitances at peripheral and external base node
C_1 = (1.0-model->HICUMfbcpar)*(here->HICUMcjcx0_scaled+here->HICUMcbcpar_scaled);
if (C_1 >= here->HICUMcbcpar_scaled) {
cjcx01 = C_1-here->HICUMcbcpar_scaled;
cjcx02 = here->HICUMcjcx0_scaled-cjcx01;
} else {
cjcx01 = 0.0;
cjcx02 = here->HICUMcjcx0_scaled;
}
//Temperature mapping for tunneling current is done inside HICTUN
hicum_TMPHICJ(vt, here->HICUMvt0, qtt0, ln_qtt0, mg,
1.0, model->HICUMvdcx, model->HICUMzcx, model->HICUMvptcx, 0, vgbc0,
&cratio_t_real, &here->HICUMvdcx_t.rpart, &here->HICUMvptcx_t.rpart,
&cratio_t_dual, &here->HICUMvdcx_t.dpart, &here->HICUMvptcx_t.dpart);
cratio_t.rpart(cratio_t_real);
cratio_t.dpart(cratio_t_dual);
a = cratio_t*cjcx01;
here->HICUMcjcx01_t.rpart = a.rpart();
here->HICUMcjcx01_t.dpart = a.dpart();
a = cratio_t*cjcx02;
here->HICUMcjcx02_t.rpart = a.rpart();
here->HICUMcjcx02_t.dpart = a.dpart();
//Constant external series resistances
a = here->HICUMrcx_scaled*exp(model->HICUMzetarcx*ln_qtt0);
here->HICUMrcx_t.rpart = a.rpart();
here->HICUMrcx_t.dpart = a.dpart();
a = here->HICUMrbx_scaled*exp(model->HICUMzetarbx*ln_qtt0);
here->HICUMrbx_t.rpart = a.rpart();
here->HICUMrbx_t.dpart = a.dpart();
a = here->HICUMre_scaled*exp(model->HICUMzetare*ln_qtt0);
here->HICUMre_t.rpart = a.rpart();
here->HICUMre_t.dpart = a.dpart();
//Forward transit time in substrate transistor
a = model->HICUMtsf*exp((model->HICUMzetacx-1.0)*ln_qtt0);
here->HICUMtsf_t.rpart = a.rpart();
here->HICUMtsf_t.dpart = a.dpart();
//Capacitance for c-s junction
hicum_TMPHICJ(vt, here->HICUMvt0, qtt0, ln_qtt0, mg,
model->HICUMcjs0, model->HICUMvds, model->HICUMzs, model->HICUMvpts, 0, vgsc0,
&here->HICUMcjs0_t.rpart, &here->HICUMvds_t.rpart, &here->HICUMvpts_t.rpart,
&here->HICUMcjs0_t.dpart, &here->HICUMvds_t.dpart, &here->HICUMvpts_t.dpart);
/*Peripheral s-c capacitance
* Note, thermal update only required for model->HICUMvds > 0
* Save computional effort otherwise
*/
if (model->HICUMvdsp > 0) {
hicum_TMPHICJ(vt, here->HICUMvt0, qtt0, ln_qtt0, mg,
model->HICUMcscp0, model->HICUMvdsp, model->HICUMzsp, model->HICUMvptsp, 0, vgsc0,
&here->HICUMcscp0_t.rpart, &here->HICUMvdsp_t.rpart, &here->HICUMvptsp_t.rpart,
&here->HICUMcscp0_t.dpart, &here->HICUMvdsp_t.dpart, &here->HICUMvptsp_t.dpart);
} else {
// Avoid uninitialized variables
here->HICUMcscp0_t.rpart = model->HICUMcscp0;
here->HICUMcscp0_t.dpart = 0;
here->HICUMvdsp_t.rpart = model->HICUMvdsp;
here->HICUMvdsp_t.dpart = 0;
here->HICUMvptsp_t.rpart = model->HICUMvptsp;
here->HICUMvptsp_t.dpart = 0;
}
a = model->HICUMahjei*exp(model->HICUMzetahjei*ln_qtt0);
here->HICUMahjei_t.rpart = a.rpart();
here->HICUMahjei_t.dpart = a.dpart();
a = model->HICUMhjei*exp(model->HICUMdvgbe/vt*(exp(model->HICUMzetavgbe*log(qtt0))-1));
here->HICUMhjei0_t.rpart = a.rpart();
here->HICUMhjei0_t.dpart = a.dpart();
a = model->HICUMhf0*exp(model->HICUMdvgbe/vt*(qtt0-1));
here->HICUMhf0_t.rpart = a.rpart();
here->HICUMhf0_t.dpart = a.dpart();
if (model->HICUMflcomp >= 2.3) {
a = model->HICUMhfe*exp((model->HICUMvgb-model->HICUMvge)/vt*(qtt0-1));
here->HICUMhfe_t.rpart = a.rpart();
here->HICUMhfe_t.dpart = a.dpart();
a = model->HICUMhfc*exp((model->HICUMvgb-model->HICUMvgc)/vt*(qtt0-1));
here->HICUMhfc_t.rpart = a.rpart();
here->HICUMhfc_t.dpart = a.dpart();
} else {
here->HICUMhfe_t.rpart = model->HICUMhfe;
here->HICUMhfe_t.dpart = 0;
here->HICUMhfc_t.rpart = model->HICUMhfc;
here->HICUMhfc_t.dpart = 0;
}
a = here->HICUMrth_scaled*exp(model->HICUMzetarth*ln_qtt0)*(1+model->HICUMalrth*dT);
here->HICUMrth_t.rpart = a.rpart();
here->HICUMrth_t.dpart = a.dpart();
return(0);
}

17
src/spicelib/devices/hicum2/hicumL2temp.hpp

@ -0,0 +1,17 @@
/**********
License : 3-clause BSD
Spice3 Implementation: 2019-2020 Dietmar Warning, Markus Müller, Mario Krattenmacher
Model Author : 1990 Michael Schröter TU Dresden
**********/
#ifndef hicumL2_temp
#define hicumL2_temp
#include "hicum2defs.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* hicumL2_temp */

6
src/spicelib/parser/inp2q.c

@ -17,11 +17,11 @@ model_numnodes(int type)
{ {
#ifdef ADMS #ifdef ADMS
if (type == INPtypelook("hicum0") || if (type == INPtypelook("hicum0") ||
type == INPtypelook("hicum2") ||
type == INPtypelook("bjt504t")) type == INPtypelook("bjt504t"))
return 5; return 5;
#else #else
if (type == INPtypelook("VBIC"))
if (type == INPtypelook("VBIC") ||
type == INPtypelook("hicum2"))
return 5; return 5;
#endif #endif
@ -101,9 +101,9 @@ void INP2Q(CKTcircuit *ckt, INPtables * tab, struct card *current, CKTnode *gnod
#endif #endif
#ifdef ADMS #ifdef ADMS
thismodel->INPmodType != INPtypelook("hicum0") && thismodel->INPmodType != INPtypelook("hicum0") &&
thismodel->INPmodType != INPtypelook("hicum2") &&
thismodel->INPmodType != INPtypelook("bjt504t") && thismodel->INPmodType != INPtypelook("bjt504t") &&
#endif #endif
thismodel->INPmodType != INPtypelook("hicum2") &&
thismodel->INPmodType != INPtypelook("VBIC")) thismodel->INPmodType != INPtypelook("VBIC"))
{ {
LITERR("incorrect model type"); LITERR("incorrect model type");

2
src/spicelib/parser/inpdomod.c

@ -78,6 +78,7 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
"Device type HICUM0 not available in this binary\n"); "Device type HICUM0 not available in this binary\n");
} }
break; break;
#endif
case 8: case 8:
type = INPtypelook("hicum2"); type = INPtypelook("hicum2");
if(type < 0) { if(type < 0) {
@ -85,7 +86,6 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
"Device type HICUM2 not available in this binary\n"); "Device type HICUM2 not available in this binary\n");
} }
break; break;
#endif
default: /* placeholder; use level 4 for the next model */ default: /* placeholder; use level 4 for the next model */
#ifdef ADMS #ifdef ADMS
err = INPmkTemp( err = INPmkTemp(

1
tests/Makefile.am

@ -27,6 +27,7 @@ DIST_SUBDIRS = \
filters \ filters \
general \ general \
hfet \ hfet \
hicum2 \
hisim \ hisim \
hisimhv1 \ hisimhv1 \
hisimhv2 \ hisimhv2 \

686
tests/bin/ads.pm

@ -0,0 +1,686 @@
#
# ads DC, AC and noise test routines
#
#
# Rel Date Who Comments
# ==== ========== ============= ========
# 1.3 06/21/07 Colin McAndrew Verilog-A model support added
# 1.2 06/30/06 Colin McAndrew Floating node support added
# Noise simulation added
# 1.0 04/13/06 Rick Poore/ Initial version
# Colin McAndrew
#
package simulate;
$simulatorCommand="hpeesofsim_local";
$netlistFile="adsCkt";
$mFactorVerilogaName="m"; # for LRM2.1
#$mFactorVerilogaName="_M"; # for LRM2.2
use strict;
sub version {
my($version,@Field);
if (!open(SIMULATE,"$simulate::simulatorCommand -version 2>/dev/null|")) {
die("ERROR: cannot run $main::simulatorName, stopped");
}
$version="unknown";
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
if (/HPEESOFSIM/i) {
@Field=split;
$version=$Field[2];
}
}
close(SIMULATE);
if (! $main::debug) {
unlink($simulate::netlistFile);
}
return($version);
}
sub runNoiseTest {
my($variant,$outputFile)=@_;
my($i,@Field,$arg,$name,$value,$type,$pin,$noisePin);
my(@BiasList,$realVal,$imagVal);
my($start,$stop,$step,$sign,$inResults,%Index,$iVariables);
my(@X,@Noise,$temperature,$biasVoltage,$sweepVoltage);
my(@realAdsResults,@imagAdsResults);
#
# Make up the netlist, using a subckt to encapsulate the
# instance. This simplifies handling of the variants as
# the actual instance is driven by voltage-controlled
# voltage sources from the subckt pins, and the currents
# are fed back to the subckt pins using current-controlled
# current sources. Pin swapping, polarity reversal, and
# m-factor scaling can all be handled by simple modifications
# of this subckt.
#
@X=();@Noise=();
$noisePin=$main::Outputs[0];
($start,$stop,$step)=split(/\s+/,$main::biasSweepSpec);
foreach $temperature (@main::Temperature) {
foreach $biasVoltage (split(/\s+/,$main::biasListSpec)) {
if ($main::fMin == $main::fMax) {
push(@X,@main::BiasSweepList);
}
if (!open(OF,">$simulate::netlistFile")) {
die("ERROR: cannot open file $simulate::netlistFile, stopped");
}
print OF "; Noise simulation for $main::simulatorName";
print OF "Options UseNutmegFormat=yes ASCII_Rawfile=yes";
print OF "Options Temp=$temperature";
print OF "Vsweep = 0 V";
&generateCommonNetlistInfo($variant);
foreach $pin (@main::Pin) {
if ($main::isFloatingPin{$pin}) {
print OF "I_Source:i_$pin $pin 0 Idc=0";
} elsif ($pin eq $main::biasListPin) {
print OF "V_Source:v_$pin $pin 0 Vdc=$biasVoltage";
} elsif ($pin eq $main::biasSweepPin) {
if ($stop < $start) { # flip polarity as ADS always does lo->hi sweep
print OF "V_Source:v_$pin 0 $pin Vdc=Vsweep";
} else {
print OF "V_Source:v_$pin $pin 0 Vdc=Vsweep";
}
} else {
print OF "V_Source:v_$pin $pin 0 Vdc=$main::BiasFor{$pin}";
}
}
print OF "mysub:x_$noisePin ".join(" ",@main::Pin);
print OF "SDD:fn_$noisePin 0 n_$noisePin I[1,0]=_c1 C[1]=\"v_$noisePin\"";
print OF "R:r_$noisePin n_$noisePin 0 R=1 Noise=no";
print OF "OutputPlan:noiseOutput Type=\"Output\"";
if ($main::fType eq "lin") {
print OF "SweepPlan:noisePlan Start=$main::fMin Stop=$main::fMax Lin=$main::fSteps";
} elsif ($main::fType eq "dec") {
print OF "SweepPlan:noisePlan Start=$main::fMin Stop=$main::fMax Dec=$main::fSteps";
} else { # octal sweep
print OF "SweepPlan:noisePlan Start=$main::fMin Stop=$main::fMax Dec=".(int($main::fSteps*log(10)/log(2)));
}
if ($stop < $start) {
$sign=-1;
print OF "SweepPlan:dcPlan Start=".(-1)*$start." Stop=".(-1)*$stop." Step=".(-1)*$step;
} else {
$sign=1;
print OF "SweepPlan:dcPlan Start=$start Stop=$stop Step=$step";
}
print OF "AC:AC1 CalcNoise=yes OutputPlan=\"noiseOutput\" SweepVar=\"freq\" \\";
print OF "SweepPlan=\"noisePlan\" NoiseNode=\"n_$noisePin\"";
print OF "ParamSweep:Vsweep SimInstanceName=\"AC1\" SweepVar=\"Vsweep\" SweepPlan=\"dcPlan\"";
close(OF);
#
# Run simulations and get the results
#
if (!open(SIMULATE,"$simulate::simulatorCommand $simulate::netlistFile 2>/dev/null |")) {
die("ERROR: cannot run $main::simulatorName, stopped");
}
$inResults=0;
while (<SIMULATE>) {
chomp;
}
close(SIMULATE);
if (!open(SIMULATE,"spectra.raw")) {
die("ERROR: cannot open ADS spectra.raw file, stopped");
}
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
next if (/^$/);
if (/Plotname:\s*AC/) {
$inResults=0;next;
}
if (/Plotname:\s*CT/) {
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
last if (/^$/);
}
next;
}
if (s/^Variables:\s*//) {
$iVariables=0;
@Field=split;
$Index{$Field[1]}=$Field[0];
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
if (/^Values:/) {
$inResults=1;last;
}
++$iVariables;
@Field=split;
$Index{$Field[1]}=$Field[0];
}
@realAdsResults=();@imagAdsResults=();
next;
}
next if (!$inResults);
s/,/ /;
@Field=split;
shift(@Field) if ($#Field == 2);
push(@realAdsResults,$Field[0]);
push(@imagAdsResults,$Field[1]);
if ($#realAdsResults == $iVariables) {
if ($main::fMin != $main::fMax) {
push(@X,1*$realAdsResults[$Index{"freq"}]);
}
push(@Noise,$realAdsResults[$Index{"n_$noisePin.noise"}]**2);
@realAdsResults=();@imagAdsResults=();
}
}
close(SIMULATE);
}
}
#
# Write the results to a file
#
if (!open(OF,">$outputFile")) {
die("ERROR: cannot open file $outputFile, stopped");
}
if ($main::fMin == $main::fMax) {
printf OF ("V($main::biasSweepPin)");
} else {
printf OF ("Freq");
}
foreach (@main::Outputs) {
printf OF (" N($_)");
}
printf OF ("\n");
for ($i=0;$i<=$#X;++$i) {
if (defined($Noise[$i])) {printf OF ("$X[$i] $Noise[$i]\n")}
}
close(OF);
#
# Clean up, unless the debug flag was specified
#
if (! $main::debug) {
unlink($simulate::netlistFile);
unlink("$simulate::netlistFile.ds");
unlink(".spiceinit");
unlink("spectra.raw");
}
}
sub runAcTest {
my($variant,$outputFile)=@_;
my($i,@Field,$arg,$name,$value,$type,$pin,$mPin,$fPin,%NextPin);
my(@BiasList,$acStim,$realVal,$imagVal);
my($start,$stop,$step,$sign,$inResults,%Index,$iVariables);
my(@X,$omega,%g,%c,$temperature,$biasVoltage,$sweepVoltage,$twoPi);
my(@realAdsResults,@imagAdsResults,$outputLine);
$twoPi=8.0*atan2(1.0,1.0);
#
# Make up the netlist, using a subckt to encapsulate the
# instance. This simplifies handling of the variants as
# the actual instance is driven by voltage-controlled
# voltage sources from the subckt pins, and the currents
# are fed back to the subckt pins using current-controlled
# current sources. Pin swapping, polarity reversal, and
# m-factor scaling can all be handled by simple modifications
# of this subckt.
#
foreach $mPin (@main::Pin) {
foreach $fPin (@main::Pin) {
@{$g{$mPin,$fPin}}=();
@{$c{$mPin,$fPin}}=();
}
}
@X=();
($start,$stop,$step)=split(/\s+/,$main::biasSweepSpec);
foreach $temperature (@main::Temperature) {
foreach $biasVoltage (split(/\s+/,$main::biasListSpec)) {
if ($main::fMin == $main::fMax) {
push(@X,@main::BiasSweepList);
}
if (!open(OF,">$simulate::netlistFile")) {
die("ERROR: cannot open file $simulate::netlistFile, stopped");
}
print OF "; AC simulation for $main::simulatorName";
print OF "Options UseNutmegFormat=yes ASCII_Rawfile=yes";
print OF "Options Temp=$temperature";
print OF "Vsweep = 0 V";
&generateCommonNetlistInfo($variant);
foreach $fPin (@main::Pin) {
foreach $mPin (@main::Pin) {
if ($mPin eq $fPin) {
$acStim=" Vac=1";
} else {
$acStim="";
}
if ($main::isFloatingPin{$mPin}) {
print OF "I_Source:i_${mPin}_$fPin ${mPin}_$fPin 0 Idc=0";
} elsif ($mPin eq $main::biasListPin) {
print OF "V_Source:v_${mPin}_$fPin ${mPin}_$fPin 0 Vdc=$biasVoltage$acStim";
} elsif ($mPin eq $main::biasSweepPin) {
if ($stop < $start) { # flip polarity as ADS always does lo->hi sweep
$acStim=~s/1/-1/;
print OF "V_Source:v_${mPin}_$fPin 0 ${mPin}_$fPin Vdc=Vsweep$acStim";
} else {
print OF "V_Source:v_${mPin}_$fPin ${mPin}_$fPin 0 Vdc=Vsweep$acStim";
}
} else {
print OF "V_Source:v_${mPin}_$fPin ${mPin}_$fPin 0 Vdc=$main::BiasFor{$mPin}$acStim";
}
}
print OF "mysub:x_$fPin ".join("_$fPin ",@main::Pin)."_$fPin ";
}
if ($main::fType eq "lin") {
print OF "SweepPlan:acPlan Start=$main::fMin Stop=$main::fMax Lin=$main::fSteps";
} elsif ($main::fType eq "dec") {
print OF "SweepPlan:acPlan Start=$main::fMin Stop=$main::fMax Dec=$main::fSteps";
} else { # octal sweep
print OF "SweepPlan:acPlan Start=$main::fMin Stop=$main::fMax Dec=".(int($main::fSteps*log(10)/log(2)));
}
if ($stop < $start) {
$sign=-1;
print OF "SweepPlan:dcPlan Start=".(-1)*$start." Stop=".(-1)*$stop." Step=".(-1)*$step;
} else {
$sign=1;
print OF "SweepPlan:dcPlan Start=$start Stop=$stop Step=$step";
}
print OF "OutputPlan:acOutput Type=\"Output\" UseNodeNestLevel=yes NodeNestLevel=2 UseEquationNestLevel=yes EquationNestLevel=2";
print OF "AC:AC1 OutputPlan=\"acOutput\" SweepVar=\"freq\" SweepPlan=\"acPlan\"";
print OF "ParamSweep:Vsweep SimInstanceName=\"AC1\" SweepVar=\"Vsweep\" SweepPlan=\"dcPlan\"";
close(OF);
#
# Run simulations and get the results
#
if (!open(SIMULATE,"$simulate::simulatorCommand $simulate::netlistFile 2>/dev/null |")) {
die("ERROR: cannot run $main::simulatorName, stopped");
}
$inResults=0;
while (<SIMULATE>) {
chomp;
}
close(SIMULATE);
if (!open(SIMULATE,"spectra.raw")) {
die("ERROR: cannot open ADS spectra.raw file, stopped");
}
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
next if (/^$/);
if (/Plotname:\s*AC/) {
$inResults=0;next;
}
if (/Plotname:\s*CT/) {
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
last if (/^$/);
}
next;
}
if (s/^Variables:\s*//) {
$iVariables=0;
@Field=split;
$Index{$Field[1]}=$Field[0];
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
if (/^Values:/) {
$inResults=1;last;
}
++$iVariables;
@Field=split;
$Index{$Field[1]}=$Field[0];
}
@realAdsResults=();@imagAdsResults=();
next;
}
next if (!$inResults);
s/,/ /;
@Field=split;
shift(@Field) if ($#Field == 2);
push(@realAdsResults,$Field[0]);
push(@imagAdsResults,$Field[1]);
if ($#realAdsResults == $iVariables) {
if ($main::fMin != $main::fMax) {
push(@X,1*$realAdsResults[$Index{"freq"}]);
}
$omega=$twoPi*$realAdsResults[$Index{"freq"}];
foreach (@main::Outputs) {
($type,$mPin,$fPin)=split(/\s+/,$_);
push(@{$g{$mPin,$fPin}},1*$realAdsResults[$Index{"v_${mPin}_${fPin}.i"}]);
if ($mPin eq $fPin) {
push(@{$c{$mPin,$fPin}},$imagAdsResults[$Index{"v_${mPin}_${fPin}.i"}]/$omega);
} else {
push(@{$c{$mPin,$fPin}},-1*$imagAdsResults[$Index{"v_${mPin}_${fPin}.i"}]/$omega);
}
}
@realAdsResults=();@imagAdsResults=();
}
}
close(SIMULATE);
}
}
#
# Write the results to a file
#
if (!open(OF,">$outputFile")) {
die("ERROR: cannot open file $outputFile, stopped");
}
if ($main::fMin == $main::fMax) {
printf OF ("V($main::biasSweepPin)");
} else {
printf OF ("Freq");
}
foreach (@main::Outputs) {
($type,$mPin,$fPin)=split(/\s+/,$_);
printf OF (" $type($mPin,$fPin)");
}
printf OF ("\n");
for ($i=0;$i<=$#X;++$i) {
$outputLine="$X[$i]";
foreach (@main::Outputs) {
($type,$mPin,$fPin)=split(/\s+/,$_);
if ($type eq "g") {
if (defined(${$g{$mPin,$fPin}}[$i])) {
$outputLine.=" ${$g{$mPin,$fPin}}[$i]";
} else {
undef($outputLine);last;
}
} else {
if (defined(${$c{$mPin,$fPin}}[$i])) {
$outputLine.=" ${$c{$mPin,$fPin}}[$i]";
} else {
undef($outputLine);last;
}
}
}
if (defined($outputLine)) {printf OF ("$outputLine\n")}
}
close(OF);
#
# Clean up, unless the debug flag was specified
#
if (! $main::debug) {
unlink($simulate::netlistFile);
unlink("$simulate::netlistFile.ds");
unlink(".spiceinit");
unlink("spectra.raw");
}
}
sub runDcTest {
my($variant,$outputFile)=@_;
my($i,$arg,$name,$value,$pin);
my($start,$stop,$step);
my(@V,%DC,$temperature,$biasVoltage);
my($inData,$inResults,$iVariables,@Field,%Index,@AdsResults,$sign);
if (!defined($main::biasSweepPin)) {
die("ERROR: biasSweep must be specified for a DC I(V) test, stopped");
}
#
# Make up the netlist, using a subckt to encapsulate the
# instance. This simplifies handling of the variants as
# the actual instance is driven by voltage-controlled
# voltage sources from the subckt pins, and the currents
# are fed back to the subckt pins using current-controlled
# current sources. Pin swapping, polarity reversal, and
# m-factor scaling can all be handled by simple modifications
# of this subckt.
#
@V=();
foreach $pin (@main::Outputs) {@{$DC{$pin}}=()}
($start,$stop,$step)=split(/\s+/,$main::biasSweepSpec);
$start-=$step;
foreach $temperature (@main::Temperature) {
foreach $biasVoltage (split(/\s+/,$main::biasListSpec)) {
if (!open(OF,">$simulate::netlistFile")) {
die("ERROR: cannot open file $simulate::netlistFile, stopped");
}
print OF "; DC simulation for $main::simulatorName";
print OF "Options UseNutmegFormat=yes ASCII_Rawfile=yes";
print OF "Options Temp=$temperature";
&generateCommonNetlistInfo($variant);
foreach $pin (@main::Pin) {
if ($main::isFloatingPin{$pin}) {
print OF "I_Source:i_$pin $pin 0 Idc=0";
} elsif ($pin eq $main::biasListPin) {
print OF "V_Source:v_$pin $pin 0 Vdc=$biasVoltage";
} elsif ($pin eq $main::biasSweepPin) {
if ($stop < $start) { # flip polarity as ADS always does lo->hi sweep
print OF "V_Source:v_$pin 0 $pin Vdc=".(-1)*$start;
} else {
print OF "V_Source:v_$pin $pin 0 Vdc=$start";
}
} else {
print OF "V_Source:v_$pin $pin 0 Vdc=$main::BiasFor{$pin}";
}
}
print OF "mysub:x1 ".join(" ",@main::Pin);
if ($stop < $start) {
$sign=-1;
print OF "SweepPlan:dcPlan Start=".(-1)*$start." Stop=".(-1)*$stop." Step=".(-1)*$step;
} else {
$sign=1;
print OF "SweepPlan:dcPlan Start=$start Stop=$stop Step=$step";
}
print OF "DC:DC1 SweepVar=\"v_$main::biasSweepPin.Vdc\" SweepPlan=\"dcPlan\"";
close(OF);
#
# Run simulations and get the results
#
if (!open(SIMULATE,"$simulate::simulatorCommand $simulate::netlistFile 2>/dev/null |")) {
die("ERROR: cannot run $main::simulatorName, stopped");
}
$inResults=0;
while (<SIMULATE>) {
chomp;
}
close(SIMULATE);
if (!open(SIMULATE,"spectra.raw")) {
die("ERROR: cannot open ADS spectra.raw file, stopped");
}
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
if (s/^Variables:\s*//) {
$iVariables=0;
@Field=split;
$Index{$Field[1]}=$Field[0];
while (<SIMULATE>) {
chomp;s/^\s+//;s/\s+$//;
if (/^Values:/) {
$inResults=1;last;
}
++$iVariables;
@Field=split;
$Index{$Field[1]}=$Field[0];
}
@AdsResults=();
next;
}
next if (!$inResults);
@Field=split;
shift(@Field) if ($#Field == 2);
push(@AdsResults,@Field);
if ($#AdsResults == $iVariables) {
push(@V,$sign*$AdsResults[$Index{"v_$main::biasSweepPin.Vdc"}]);
foreach $pin (@main::Outputs) {
if ($pin eq $main::biasSweepPin) {
push(@{$DC{$pin}},$sign*$AdsResults[$Index{"v_$pin.i"}]);
} elsif ($main::isFloatingPin{$pin}) {
push(@{$DC{$pin}},1*$AdsResults[$Index{"$pin"}]);
} else {
push(@{$DC{$pin}},1*$AdsResults[$Index{"v_$pin.i"}]);
}
}
@AdsResults=();
}
}
close(SIMULATE);
}
}
#
# Write the results to a file
#
if (!open(OF,">$outputFile")) {
die("ERROR: cannot open file $outputFile, stopped");
}
printf OF ("V($main::biasSweepPin)");
foreach $pin (@main::Outputs) {
if ($main::isFloatingPin{$pin}) {
printf OF (" V($pin)");
} else {
printf OF (" I($pin)");
}
}
printf OF ("\n");
for ($i=0;$i<=$#V;++$i) {
next if (abs($V[$i]-$start) < abs(0.1*$step)); # this is dummy first bias point
printf OF ("$V[$i]");
foreach $pin (@main::Outputs) {printf OF (" ${$DC{$pin}}[$i]")}
printf OF ("\n");
}
close(OF);
#
# Clean up, unless the debug flag was specified
#
if (! $main::debug) {
unlink($simulate::netlistFile);
unlink("$simulate::netlistFile.ds");
unlink(".spiceinit");
unlink("spectra.raw");
}
}
sub generateCommonNetlistInfo {
my($variant)=$_[0];
my(@Pin_x,$arg,$name,$value,$eFactor,$fFactor,$pin,@Args);
foreach $pin (@main::Pin) {push(@Pin_x,"${pin}_x")}
if ($variant=~/^scale$/) {
die("ERROR: there is no scale or shrink option for ads, stopped");
}
if ($variant=~/^shrink$/) {
die("ERROR: there is no scale or shrink option for ads, stopped");
}
if ($variant=~/_P/) {
$eFactor=-1;$fFactor=1;
} else {
$eFactor=1;$fFactor=-1;
}
if ($variant=~/^m$/) {
if ($main::outputNoise) {
$fFactor/=sqrt($main::mFactor);
} else {
$fFactor/=$main::mFactor;
}
}
if (defined($main::verilogaFile)) {
print OF "";
print OF "#load \"veriloga\", \"$main::verilogaFile\";";
}
print OF " ";
print OF "define mysub (".join(" ",@Pin_x).")";
foreach $pin (@main::Pin) {
if ($main::isFloatingPin{$pin}) { # assumed "dt" thermal pin, no scaling sign change
print OF "V_Source:v_$pin ${pin} ${pin}_x Vdc=0";
} elsif ($variant=~/^Flip/ && defined($main::flipPin{$pin})) {
print OF "#uselib \"ckt\", \"VCVS\"";
print OF "VCVS:e_$pin $main::flipPin{$pin}_x 0 ${pin}_v 0 G=$eFactor";
print OF "V_Source:v_$pin ${pin}_v ${pin} Vdc=0";
print OF "SDD:f_$pin $main::flipPin{$pin}_x 0 C[1]=\"v_$pin\" I[1]=_c1*$fFactor";
} else {
print OF "#uselib \"ckt\", \"VCVS\"";
print OF "VCVS:e_$pin ${pin}_x 0 ${pin}_v 0 G=$eFactor";
print OF "V_Source:v_$pin ${pin}_v ${pin} Vdc=0";
print OF "SDD:f_$pin ${pin}_x 0 C[1]=\"v_$pin\" I[1]=_c1*$fFactor";
}
}
print OF " ";
if (defined($main::verilogaFile)) {
if ($variant=~/_P/) {
@Args=split(/\s+/,$main::pTypeSelectionArguments);
} else {
@Args=split(/\s+/,$main::nTypeSelectionArguments);
}
print OF "$Args[0]:${main::keyLetter}1 ".join(" ",@main::Pin)." \\";
foreach $arg (@Args[1..$#Args]) {
($name,$value)=split(/=/,$arg);
print OF " ".$name."=$value \\";
}
foreach $arg (@main::InstanceParameters) {
($name,$value)=split(/=/,$arg);
if ($variant=~/^scale$/) {
if ($main::isLinearScale{$name}) {
$value/=$main::scaleFactor;
} elsif ($main::isAreaScale{$name}) {
$value/=$main::scaleFactor**2;
}
}
if ($variant=~/^shrink$/) {
if ($main::isLinearScale{$name}) {
$value/=(1.0-$main::shrinkPercent*0.01);
} elsif ($main::isAreaScale{$name}) {
$value/=(1.0-$main::shrinkPercent*0.01)**2;
}
}
print OF " ".$name."=$value \\";
}
if ($variant eq "m") {
print OF " $simulate::mFactorVerilogaName=$main::mFactor \\";
}
foreach $arg (@main::ModelParameters) {
print OF " ".$arg." \\";
}
} else {
print OF "mymodel:${main::keyLetter}1 ".join(" ",@main::Pin)." \\";
foreach $arg (@main::InstanceParameters) {
($name,$value)=split(/=/,$arg);
if ($variant=~/^scale$/) {
if ($main::isLinearScale{$name}) {
$value/=$main::scaleFactor;
} elsif ($main::isAreaScale{$name}) {
$value/=$main::scaleFactor**2;
}
}
if ($variant=~/^shrink$/) {
if ($main::isLinearScale{$name}) {
$value/=(1.0-$main::shrinkPercent*0.01);
} elsif ($main::isAreaScale{$name}) {
$value/=(1.0-$main::shrinkPercent*0.01)**2;
}
}
print OF " ".ucfirst($name)."=$value \\";
}
if ($variant eq "m") {
print OF " _M=$main::mFactor \\";
}
print OF " ";
if ($variant=~/_P/) {
print OF "model mymodel $main::pTypeSelectionArguments \\";
} else {
print OF "model mymodel $main::nTypeSelectionArguments \\";
}
foreach $arg (@main::ModelParameters) {
print OF " ".ucfirst($arg)." \\";
}
}
print OF " ";
print OF "end mysub";
print OF " ";
}
1;

2
tests/bin/ngspice.pm

@ -435,7 +435,7 @@ sub generateCommonNetlistInfo {
my($variant,$temperature)=@_; my($variant,$temperature)=@_;
my(@Pin_x,$arg,$name,$value,$eFactor,$fFactor,$pin); my(@Pin_x,$arg,$name,$value,$eFactor,$fFactor,$pin);
foreach $pin (@main::Pin) {push(@Pin_x,"${pin}_x")} foreach $pin (@main::Pin) {push(@Pin_x,"${pin}_x")}
print OF ".options temp=$temperature gmin=1e-15 abstol=1e-14 reltol=1e-8";
print OF ".options temp=$temperature gmin=1e-13 abstol=1e-13 reltol=1e-3";
if ($variant=~/^scale$/) { if ($variant=~/^scale$/) {
die("ERROR: there is no scale or shrink option for ngspice, stopped"); die("ERROR: there is no scale or shrink option for ngspice, stopped");
} }

17
tests/bin/run_cmc_check

@ -19,7 +19,7 @@ if [ -z "$testProgramFlags" ] ; then
testProgramFlags="-nw" testProgramFlags="-nw"
fi fi
#testProgramFlags="-d -V"
testProgramFlags="-d -V"
help() { help() {
@ -32,6 +32,8 @@ help() {
hspice run tests and compare results hspice hspice run tests and compare results hspice
ads run tests and compare results ads
clean remove all previously generated simulation results clean remove all previously generated simulation results
NOTE: if test results exist they are not resimulated NOTE: if test results exist they are not resimulated
@ -126,6 +128,10 @@ hspice() {
run_test hspice run_test hspice
} }
ads() {
run_test ads
}
##### #####
##### clean ##### clean
@ -134,6 +140,7 @@ hspice() {
clean() { clean() {
rm -rf ${qaResultsDirectory}/ngspice ngspiceCkt* rm -rf ${qaResultsDirectory}/ngspice ngspiceCkt*
rm -rf ${qaResultsDirectory}/hspice hspiceCkt* rm -rf ${qaResultsDirectory}/hspice hspiceCkt*
rm -rf ${qaResultsDirectory}/ads adsCkt*
} }
clean_ngspice() { clean_ngspice() {
@ -144,9 +151,13 @@ clean_hspice() {
rm -rf ${qaResultsDirectory}/hspice hspiceCkt* rm -rf ${qaResultsDirectory}/hspice hspiceCkt*
} }
clean_ads() {
rm -rf ${qaResultsDirectory}/ads adsCkt*
}
all() { all() {
ngspice hspice
ngspice hspice ads
} }
@ -172,7 +183,7 @@ done
for arg in $@ ; do for arg in $@ ; do
case "$arg" in case "$arg" in
all | clean | clean_ngspice | ngspice | clean_hspice | hspice)
all | clean | clean_ngspice | ngspice | clean_hspice | hspice | clean_ads | ads)
"$arg" "$arg"
;; ;;
*) *)

37
tests/hicum2/FG.cir

@ -0,0 +1,37 @@
HICUML2 v2.4.0 Gummel Test
VE Q1_E 0 1.0
VC Q1_C 0 0.0
VB Q1_B 0 0.0
RT Q1_T 0 1M
Q1 Q1_C Q1_B Q1_E Q1_E Q1_T P1 icVB=0.2 icVC=0.2 dt=0.0
.DC VE -0.2 -1.2 -10m
* .DC VE -0.2 -0.21 -10m
.print dc abs(i(vc)) abs(i(vb))
* @Q1[area] @Q1[icvbe] @Q1[icvce] @Q1[temp] @Q1[m] @Q1[vbe] @Q1[vbc] @Q1[vce] @Q1[vsc] @Q1[ic] @Q1[ib] @Q1[ie] @Q1[iavl] @Q1[is] @Q1[rcx_t] @Q1[re_t] @Q1[rbi] @Q1[rb] @Q1[betadc] @Q1[gmi] @Q1[gms] @Q1[rpii] @Q1[rpix] @Q1[rmui] @Q1[rmux] @Q1[roi] @Q1[cpii] @Q1[cpix] @Q1[cmui] @Q1[cmux] @Q1[ccs] @Q1[betaac] @Q1[crbi] @Q1[tf] @Q1[ft] @Q1[p] @Q1[tk] @Q1[dtsh]
.MODEL P1 NPN LEVEL=8
+ c10=9.074e-030 qp0=1.008e-013 hfe=10.01 hfc=20.04 hjei=3.382 hjci=0.2
+ ibeis=1.328e-019 mbei=1.027 ireis=1.5e-014 mrei=2 ibeps=1.26e-019 mbep=1.042
+ ireps=1.8e-014 mrep=1.8 mcf=1 tbhrec=1e-010 ibcis=4.603e-017 mbci=1.15
+ ibcxs=0 mbcx=1 ibets=0.02035 abet=24 tunode=1 favl=18.96 qavl=5.092e-014
+ alfav=-0.0024 alqav=-0.0006284 rbi0=4.444 rbx=2.568 fgeo=0.7409 fdqr0=0
+ fcrbi=0 fqi=1 re=1.511 rcx=2.483 itss=0 msf=1 iscs=0 msc=1
+ tsf=0 rsu=0 csu=0 cjei0=8.869e-015 vdei=0.714 zei=0.2489 ajei=1.65
+ cjep0=2.178e-015 vdep=0.8501 zep=0.2632 ajep=1.6 cjci0=3.58e-015 vdci=0.8201
+ zci=0.2857 vptci=1.79 cjcx0=6.299e-015 vdcx=0.8201 zcx=0.2863 vptcx=1.977
+ fbcpar=0.3 fbepar=1 cjs0=2.6e-014 vds=0.9997 zs=0.4295 vpts=100
+ t0=2.089e-013 dt0h=8e-014 tbvl=8.25e-014 tef0=3.271e-013 gtfe=3.548 thcs=5.001e-012
+ ahc=0.05 fthc=0.7 rci0=9.523 vlim=0.6999 vces=0.01 vpt=2 tr=0
+ cbepar=2.609e-014 cbcpar=1.64512e-014 alqf=0.166667 alit=0.333333 flnqs=0 kf=0
+ af=2 cfbe=-1 latb=0 latl=0 vgb=0.91 alt0=0.004 kt0=6.588e-005
+ zetaci=0.58 alvs=0.001 alces=-0.2286 zetarbi=0.3002 zetarbx=0.06011 zetarcx=-0.02768
+ zetare=-0.9605 zetacx=0 vge=1.17 vgc=1.17 vgs=1.17 f1vg=-0.000102377 f2vg=0.00043215
+ zetact=5 zetabet=4.892 flsh=0 rth=1113.4 cth=6.841e-012 zetarth=0
+ alrth=0.002 flcomp=2.4 tnom=26.85 acbar=1.5 flcono=0 icbar=0.01
+ vcbar=0.04 zetavgbe=0.7 hf0=40 ahjei=3 rhjei=2 delck=2 zetahjei=-0.5
.END

112
tests/hicum2/FG.out

@ -0,0 +1,112 @@
No. of Data Rows : 101
Circuit: HICUML2 v2.4.0 Gummel Test
Doing analysis at TEMP = 300.150000 and TNOM = 300.150000
HICUM2 v2.4.0 Gummel Test
--------------------------------------------------------------------------------
Index v-sweep abs(i(vc)) abs(i(vb))
--------------------------------------------------------------------------------
0 2.000000e-01 4.049275e-13 2.228959e-12
1 2.100000e-01 5.113338e-13 2.714122e-12
2 2.200000e-01 6.630638e-13 3.309110e-12
3 2.300000e-01 8.814204e-13 4.039392e-12
4 2.400000e-01 1.197716e-12 4.936361e-12
5 2.500000e-01 1.657977e-12 6.038721e-12
6 2.600000e-01 2.329849e-12 7.394200e-12
7 2.700000e-01 3.312756e-12 9.061656e-12
8 2.800000e-01 4.752819e-12 1.111369e-11
9 2.900000e-01 6.864784e-12 1.363988e-11
10 3.000000e-01 9.964231e-12 1.675076e-11
11 3.100000e-01 1.451491e-11 2.058275e-11
12 3.200000e-01 2.119828e-11 2.530429e-11
13 3.300000e-01 3.101563e-11 3.112340e-11
14 3.400000e-01 4.543821e-11 3.829703e-11
15 3.500000e-01 6.662754e-11 4.714276e-11
16 3.600000e-01 9.775923e-11 5.805316e-11
17 3.700000e-01 1.434984e-10 7.151385e-11
18 3.800000e-01 2.106980e-10 8.812576e-11
19 3.900000e-01 3.094239e-10 1.086330e-10
20 4.000000e-01 4.544605e-10 1.339576e-10
21 4.100000e-01 6.675208e-10 1.652431e-10
22 4.200000e-01 9.804908e-10 2.039088e-10
23 4.300000e-01 1.440191e-09 2.517182e-10
24 4.400000e-01 2.115368e-09 3.108651e-10
25 4.500000e-01 3.106946e-09 3.840828e-10
26 4.600000e-01 4.563079e-09 4.747811e-10
27 4.700000e-01 6.701218e-09 5.872227e-10
28 4.800000e-01 9.840494e-09 7.267467e-10
29 4.900000e-01 1.444919e-08 9.000562e-10
30 5.000000e-01 2.121433e-08 1.115590e-09
31 5.100000e-01 3.114373e-08 1.384002e-09
32 5.200000e-01 4.571544e-08 1.718799e-09
33 5.300000e-01 6.709676e-08 2.137132e-09
34 5.400000e-01 9.846489e-08 2.660929e-09
35 5.500000e-01 1.444763e-07 3.318308e-09
36 5.600000e-01 2.119536e-07 4.145522e-09
37 5.700000e-01 3.108897e-07 5.189556e-09
38 5.800000e-01 4.559164e-07 6.511663e-09
39 5.900000e-01 6.684482e-07 8.192167e-09
40 6.000000e-01 9.798144e-07 1.033707e-08
41 6.100000e-01 1.435828e-06 1.308719e-08
42 6.200000e-01 2.103455e-06 1.663074e-08
43 6.300000e-01 3.080525e-06 2.122105e-08
44 6.400000e-01 4.509880e-06 2.720120e-08
45 6.500000e-01 6.596844e-06 3.503877e-08
46 6.600000e-01 9.647940e-06 4.537475e-08
47 6.700000e-01 1.410226e-05 5.909275e-08
48 6.800000e-01 2.059972e-05 7.741690e-08
49 6.900000e-01 3.006819e-05 1.020505e-07
50 7.000000e-01 4.385020e-05 1.353718e-07
51 7.100000e-01 6.388229e-05 1.807107e-07
52 7.200000e-01 9.294511e-05 2.427359e-07
53 7.300000e-01 1.350039e-04 3.279924e-07
54 7.400000e-01 1.956548e-04 4.456394e-07
55 7.500000e-01 2.826782e-04 6.084386e-07
56 7.600000e-01 4.066653e-04 8.340431e-07
57 7.700000e-01 5.816221e-04 1.146610e-06
58 7.800000e-01 8.253658e-04 1.578709e-06
59 7.900000e-01 1.159449e-03 2.173417e-06
60 8.000000e-01 1.608349e-03 2.986417e-06
61 8.100000e-01 2.197834e-03 4.087850e-06
62 8.200000e-01 2.952755e-03 5.563725e-06
63 8.300000e-01 3.894822e-03 7.516722e-06
64 8.400000e-01 5.040995e-03 1.006634e-05
65 8.500000e-01 6.402781e-03 1.334838e-05
66 8.600000e-01 7.986391e-03 1.751363e-05
67 8.700000e-01 9.793400e-03 2.272603e-05
68 8.800000e-01 1.182159e-02 2.916016e-05
69 8.900000e-01 1.406575e-02 3.699861e-05
70 9.000000e-01 1.651838e-02 4.642947e-05
71 9.100000e-01 1.917019e-02 5.764474e-05
72 9.200000e-01 2.201052e-02 7.084062e-05
73 9.300000e-01 2.502762e-02 8.622214e-05
74 9.400000e-01 2.820878e-02 1.040182e-04
75 9.500000e-01 3.154025e-02 1.245245e-04
76 9.600000e-01 3.500674e-02 1.482245e-04
77 9.700000e-01 3.858976e-02 1.761297e-04
78 9.800000e-01 4.226323e-02 2.106934e-04
79 9.900000e-01 4.598348e-02 2.579408e-04
80 1.000000e+00 4.967483e-02 3.308659e-04
81 1.010000e+00 5.323301e-02 4.499557e-04
82 1.020000e+00 5.657993e-02 6.330012e-04
83 1.030000e+00 5.972028e-02 8.813991e-04
84 1.040000e+00 6.271680e-02 1.181850e-03
85 1.050000e+00 6.563508e-02 1.518125e-03
86 1.060000e+00 6.852092e-02 1.878222e-03
87 1.070000e+00 7.140176e-02 2.255370e-03
88 1.080000e+00 7.429288e-02 2.646645e-03
89 1.090000e+00 7.720226e-02 3.051443e-03
90 1.100000e+00 8.013339e-02 3.470405e-03
91 1.110000e+00 8.308694e-02 3.904762e-03
92 1.120000e+00 8.606171e-02 4.355986e-03
93 1.130000e+00 8.905522e-02 4.825594e-03
94 1.140000e+00 9.206412e-02 5.315066e-03
95 1.150000e+00 9.508446e-02 5.825795e-03
96 1.160000e+00 9.811193e-02 6.359080e-03
97 1.170000e+00 1.011420e-01 6.916117e-03
98 1.180000e+00 1.041701e-01 7.498008e-03
99 1.190000e+00 1.071917e-01 8.105763e-03
100 1.200000e+00 1.102022e-01 8.740302e-03

34
tests/hicum2/FG_sh.cir

@ -0,0 +1,34 @@
HICUML2 v2.4.0 Gummel Test
VE Q1_E 0 1.0
VC Q1_C 0 0.0
VB Q1_B 0 0.0
RT Q1_T 0 1M
Q1 Q1_C Q1_B Q1_E Q1_E Q1_T P1
.DC VE -0.2 -1.2 -10m
.OPTIONS GMIN=1e-13 NOACCT
.print dc abs(i(vc)) abs(i(vb))
.MODEL P1 NPN LEVEL=8
+ c10=9.074e-030 qp0=1.008e-013 hfe=10.01 hfc=20.04 hjei=3.382 hjci=0.2
+ ibeis=1.328e-019 mbei=1.027 ireis=1.5e-014 mrei=2 ibeps=1.26e-019 mbep=1.042
+ ireps=1.8e-014 mrep=1.8 mcf=1 tbhrec=1e-010 ibcis=4.603e-017 mbci=1.15
+ ibcxs=0 mbcx=1 ibets=0.02035 abet=24 tunode=1 favl=18.96 qavl=5.092e-014
+ alfav=-0.0024 alqav=-0.0006284 rbi0=4.444 rbx=2.568 fgeo=0.7409 fdqr0=0
+ fcrbi=0 fqi=1 re=1.511 rcx=2.483 itss=0 msf=1 iscs=0 msc=1
+ tsf=0 rsu=0 csu=0 cjei0=8.869e-015 vdei=0.714 zei=0.2489 ajei=1.65
+ cjep0=2.178e-015 vdep=0.8501 zep=0.2632 ajep=1.6 cjci0=3.58e-015 vdci=0.8201
+ zci=0.2857 vptci=1.79 cjcx0=6.299e-015 vdcx=0.8201 zcx=0.2863 vptcx=1.977
+ fbcpar=0.3 fbepar=1 cjs0=2.6e-014 vds=0.9997 zs=0.4295 vpts=100
+ t0=2.089e-013 dt0h=8e-014 tbvl=8.25e-014 tef0=3.271e-013 gtfe=3.548 thcs=5.001e-012
+ ahc=0.05 fthc=0.7 rci0=9.523 vlim=0.6999 vces=0.01 vpt=2 tr=0
+ cbepar=2.609e-014 cbcpar=1.64512e-014 alqf=0.166667 alit=0.333333 flnqs=1 kf=0
+ af=2 cfbe=-1 latb=0 latl=0 vgb=0.91 alt0=0.004 kt0=6.588e-005
+ zetaci=0.58 alvs=0.001 alces=-0.2286 zetarbi=0.3002 zetarbx=0.06011 zetarcx=-0.02768
+ zetare=-0.9605 zetacx=0 vge=1.17 vgc=1.17 vgs=1.17 f1vg=-0.000102377 f2vg=0.00043215
+ zetact=5 zetabet=4.892 flsh=1 rth=1113.4 cth=6.841e-012 zetarth=0
+ alrth=0.002 flcomp=2.4 tnom=26.85 acbar=1.5 flcono=0 icbar=0.01
+ vcbar=0.04 zetavgbe=0.7 hf0=40 ahjei=3 rhjei=2 delck=2 zetahjei=-0.5
.END

15
tests/hicum2/Makefile.am

@ -0,0 +1,15 @@
## Process this file with automake to produce Makefile.in
TESTS = FG.cir \
FG_sh.cir
TESTS_ENVIRONMENT = $(SHELL) $(top_srcdir)/tests/bin/check.sh $(top_builddir)/src/ngspice
EXTRA_DIST = \
$(TESTS) \
$(TESTS:.cir=.out)
MAINTAINERCLEANFILES = Makefile.in

41
tests/hicum2/npn/parameters/compare_para.pl

@ -0,0 +1,41 @@
#use warnings
#use strict
my $va_code = '../vacode/hicumL2V2p33.va';
my %ref_para = ();
open(FILE, "<$va_code");
while (<FILE>) {
my ($dummy, $name, $value) = /parameter\s*(real|integer)\s*(\w+)\s*=\s*([+-]?\d+(\.\d+)?([Ee][+-]?\d+)?)/;
$ref_para{$name} = $value;
}
my @para_names = keys %ref_para;
close(FILE);
my @parameters = ('npn_1D','npn_cornoise','npn_full','npn_full_sh','npn_full_subcoupl','npn_full_subtran','npn_internal','npn_lat_nqs','npn_vert_nqs');
foreach my $set (@parameters) {
open(FILE,"<$set");
my %act_para = ();
while (<FILE>) {
my ($name, $value) = /\+\s?(\w+)\s?=\s?\(\s?([+-]?\d+(\.\d+)?([Ee][+-]?\d+)?)\s?\)/;
$act_para{$name} = $value;
}
my @neq = grep { $ref_para{$_} != $act_para{$_} } @para_names;
my @eq = grep { $ref_para{$_} == $act_para{$_} } @para_names;
my $percentage = ($#neq/$#para_names)*100;
print "$set : $percentage\n";
#print join(' ', @eq), "\n";
close(FILE);
}

125
tests/hicum2/npn/parameters/npn_1D

@ -0,0 +1,125 @@
+ c10 = ( 9.074e-030 )
+ qp0 = ( 1.008e-013 )
+ ich = ( 0 )
+ hfe = ( 10.01 )
+ hfc = ( 20.04 )
+ hjei = ( 3.382 )
+ hjci = ( 0.2 )
+ ibeis = ( 1.328e-019 )
+ mbei = ( 1.027 )
+ ireis = ( 1.5e-014 )
+ mrei = ( 2 )
+ ibeps = ( 0 )
+ mbep = ( 1 )
+ ireps = ( 0 )
+ mrep = ( 2 )
+ mcf = ( 1 )
+ tbhrec = ( 1e-010 )
+ ibcis = ( 4.603e-017 )
+ mbci = ( 1.15 )
+ ibcxs = ( 0 )
+ mbcx = ( 1 )
+ ibets = ( 0 )
+ abet = ( 40 )
+ tunode = ( 1 )
+ favl = ( 18.96 )
+ qavl = ( 5.092e-014 )
+ alfav = ( -0.0024 )
+ alqav = ( -0.0006284 )
+ rbi0 = ( 0 )
+ rbx = ( 0 )
+ fgeo = ( 0.6557 )
+ fdqr0 = ( 0 )
+ fcrbi = ( 0 )
+ fqi = ( 1 )
+ re = ( 0 )
+ rcx = ( 0 )
+ itss = ( 0 )
+ msf = ( 1 )
+ iscs = ( 0 )
+ msc = ( 1 )
+ tsf = ( 0 )
+ rsu = ( 0 )
+ csu = ( 0 )
+ cjei0 = ( 8.869e-015 )
+ vdei = ( 0.714 )
+ zei = ( 0.2489 )
+ ajei = ( 1.65 )
+ cjep0 = ( 1e-020 )
+ vdep = ( 0.9 )
+ zep = ( 0.5 )
+ ajep = ( 2.5 )
+ cjci0 = ( 3.58e-015 )
+ vdci = ( 0.8201 )
+ zci = ( 0.2857 )
+ vptci = ( 1.79 )
+ cjcx0 = ( 1e-020 )
+ vdcx = ( 0.7 )
+ zcx = ( 0.4 )
+ vptcx = ( 100 )
+ fbcpar = ( 0 )
+ fbepar = ( 1 )
+ cjs0 = ( 0 )
+ vds = ( 0.6 )
+ zs = ( 0.5 )
+ vpts = ( 100 )
+ t0 = ( 2.089e-013 )
+ dt0h = ( 8e-014 )
+ tbvl = ( 8.25e-014 )
+ tef0 = ( 3.271e-013 )
+ gtfe = ( 3.548 )
+ thcs = ( 5.001e-012 )
+ ahc = ( 0.05 )
+ fthc = ( 0.7 )
+ rci0 = ( 9.523 )
+ vlim = ( 0.6999 )
+ vces = ( 0.01 )
+ vpt = ( 2 )
+ tr = ( 0 )
+ cbepar = ( 0 )
+ cbcpar = ( 0 )
+ alqf = ( 0.166667 )
+ alit = ( 0.333333 )
+ flnqs = ( 0 )
+ kf = ( 0 )
+ af = ( 2 )
+ cfbe = ( -1 )
+ latb = ( 0 )
+ latl = ( 0 )
+ vgb = ( 0.91 )
+ alt0 = ( 0.004 )
+ kt0 = ( 6.588e-005 )
+ zetaci = ( 0.58 )
+ alvs = ( 0.001 )
+ alces = ( -0.2286 )
+ zetarbi = ( 0 )
+ zetarbx = ( 0 )
+ zetarcx = ( 0 )
+ zetare = ( 0 )
+ zetacx = ( 1 )
+ vge = ( 1.17 )
+ vgc = ( 1.17 )
+ vgs = ( 1.17 )
+ f1vg = ( -0.000102377 )
+ f2vg = ( 0.00043215 )
+ zetact = ( 5 )
+ zetabet = ( 4.892 )
+ alb = ( 0 )
+ flsh = ( 0 )
+ rth = ( 0 )
+ cth = ( 0 )
+ zetarth = ( 0 )
+ alrth = ( 0 )
+ flcomp = ( 2.3 )
+ tnom = ( 26.85 )
+ dt = ( 0 )
+ acbar = ( 1.5 )
+ flcono = ( 0 )
+ icbar = ( 0.01 )
+ vcbar = ( 0.04 )
+ zetavgbe = ( 0.7 )
+ hf0 = ( 40 )
+ ahjei = ( 3 )
+ rhjei = ( 2 )
+ delck = ( 2 )
+ zetahjei = ( -0.5 )

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save