From 1894f6e86d68fd5e39ac45ee85a9a6edcdffb703 Mon Sep 17 00:00:00 2001 From: Joey Delport Date: Thu, 4 Aug 2022 16:54:15 +0200 Subject: [PATCH] Update adding CPR to JJ model. Code cleanup --- CMakeLists.txt | 2 +- docs/index.md | 6 +- docs/jp/index_jp.md | 6 +- docs/jp/syntax_jp.md | 5 + docs/refer.bib | 27 +- docs/syntax.md | 5 + include/JoSIM/AnalysisType.hpp | 14 +- include/JoSIM/BasicComponent.hpp | 130 ++- include/JoSIM/CCCS.hpp | 57 +- include/JoSIM/CCVS.hpp | 117 ++- include/JoSIM/Capacitor.hpp | 78 +- include/JoSIM/CliOptions.hpp | 48 +- include/JoSIM/Components.hpp | 63 +- include/JoSIM/Constants.hpp | 26 +- include/JoSIM/CurrentSource.hpp | 34 +- include/JoSIM/Errors.hpp | 421 ++++---- include/JoSIM/FileOutputType.hpp | 79 +- include/JoSIM/Function.hpp | 101 +- include/JoSIM/IV.hpp | 25 +- include/JoSIM/Inductor.hpp | 87 +- include/JoSIM/Input.hpp | 93 +- include/JoSIM/JJ.hpp | 164 +-- include/JoSIM/LUSolve.hpp | 66 +- include/JoSIM/LineInput.hpp | 83 +- include/JoSIM/Matrix.hpp | 67 +- include/JoSIM/Misc.hpp | 119 +-- include/JoSIM/Model.hpp | 188 ++-- include/JoSIM/Netlist.hpp | 115 +-- include/JoSIM/Noise.hpp | 16 +- include/JoSIM/Output.hpp | 52 +- include/JoSIM/ParameterName.hpp | 67 +- include/JoSIM/Parameters.hpp | 80 +- include/JoSIM/PhaseSource.hpp | 40 +- include/JoSIM/ProgressBar.hpp | 132 ++- include/JoSIM/RelevantTrace.hpp | 106 +- include/JoSIM/Resistor.hpp | 72 +- include/JoSIM/Simulation.hpp | 97 +- include/JoSIM/Spread.hpp | 26 +- include/JoSIM/Transient.hpp | 85 +- include/JoSIM/TransmissionLine.hpp | 136 +-- include/JoSIM/TypeDefines.hpp | 26 +- include/JoSIM/VCCS.hpp | 86 +- include/JoSIM/VCVS.hpp | 67 +- include/JoSIM/Verbose.hpp | 23 +- include/JoSIM/VoltageSource.hpp | 55 +- include/spline.h | 1076 ++++++++++--------- src/CCCS.cpp | 150 +-- src/CCVS.cpp | 179 ++-- src/Capacitor.cpp | 35 +- src/CliOptions.cpp | 314 +++--- src/CurrentSource.cpp | 38 +- src/Errors.cpp | 1534 ++++++++++++++-------------- src/Function.cpp | 925 +++++++++-------- src/IV.cpp | 37 +- src/Inductor.cpp | 35 +- src/Input.cpp | 79 +- src/JJ.cpp | 117 +-- src/LUSolve.cpp | 21 +- src/Matrix.cpp | 373 ++++--- src/Misc.cpp | 161 +-- src/Model.cpp | 36 +- src/Netlist.cpp | 42 +- src/Noise.cpp | 7 +- src/Output.cpp | 119 ++- src/Parameters.cpp | 958 +++++++++-------- src/PhaseSource.cpp | 19 +- src/RelevantTrace.cpp | 252 ++--- src/Resistor.cpp | 42 +- src/Simulation.cpp | 573 +++++------ src/Spread.cpp | 17 +- src/Transient.cpp | 23 +- src/TransmissionLine.cpp | 129 +-- src/VCCS.cpp | 131 +-- src/VCVS.cpp | 160 +-- src/Verbose.cpp | 130 +-- src/VoltageSource.cpp | 20 +- src/josim.cpp | 34 +- 77 files changed, 5476 insertions(+), 5682 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 662a8182..5b6602e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(JoSIM VERSION 2.6.3) +project(JoSIM VERSION 2.6.4) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/docs/index.md b/docs/index.md index a5f26296..b67adbf4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,12 +1,12 @@ # JoSIM - Superconducting Circuit Simulator -Developers Manual for v2.5.1 +Developers Manual for v2.6.4 ## Project Status -### Testing: v2.6 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoSIM-CI-Devel?branchName=testing)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=1&branchName=testing) +### Testing: v2.6.4 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoSIM-CI-Devel?branchName=testing)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=1&branchName=testing) -### Stable: v2.6 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoeyDelp.JoSIM?branchName=master)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=3&branchName=master) +### Stable: v2.6.4 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoeyDelp.JoSIM?branchName=master)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=3&branchName=master) ## Introduction diff --git a/docs/jp/index_jp.md b/docs/jp/index_jp.md index feaa97a6..2f500adb 100644 --- a/docs/jp/index_jp.md +++ b/docs/jp/index_jp.md @@ -1,12 +1,12 @@ # JoSIM - 超伝導回路シミュレータ -Developers Manual for v2.5.1 +Developers Manual for v2.6.4 ## プロジェクトの状況 -### Testing: v2.6 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoSIM-CI-Devel?branchName=testing)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=1&branchName=testing) +### Testing: v2.6.4 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoSIM-CI-Devel?branchName=testing)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=1&branchName=testing) -### Stable: v2.6 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoeyDelp.JoSIM?branchName=master)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=3&branchName=master) +### Stable: v2.6.4 - Status: [![Build Status](https://joeydelp.visualstudio.com/JoSIM/_apis/build/status/JoeyDelp.JoSIM?branchName=master)](https://joeydelp.visualstudio.com/JoSIM/_build/latest?definitionId=3&branchName=master) ## はじめに diff --git a/docs/jp/syntax_jp.md b/docs/jp/syntax_jp.md index 7d64742a..4268297e 100644 --- a/docs/jp/syntax_jp.md +++ b/docs/jp/syntax_jp.md @@ -106,6 +106,7 @@ JoSIMで現在サポートしている接合モデルはRCSJモデルだけで | D | 0.0, 1 | 0.0 | 電流位相関係に影響する接点の透過率 | | ICFCT or ICFACT | 0, 1 | $\frac{\pi}{4}$ | 臨界電流の準粒子ステップ高さに対する比 | | PHI | 0, $2\pi$ | 0 | $\pi$-junctionのようなphi-junctionを実現可能にする | +| CPR | 0,$\infty$ | 1 | 電流の位相関係定数を設定します。 | *.model* の行はサブサーキット固有であるため同じ名前の異なるモデルを分離されたサブサーキット下にそれぞれ置くことができます。サブサーキット下にモデルが見つからなかった場合グローバルなものを探すことになり、それでも見つからない場合はデフォルトの値(デフォルトのモデル)が使用されます。 @@ -113,6 +114,8 @@ JoSIMで現在サポートしている接合モデルはRCSJモデルだけで モデルの**PHI**パラメータを設定することで、JJ電流の$\sin(\phi)$部分の中にある位相($\phi$)から常に引いたものが位相の値になります。これによって$\pi$-junctionのような素子をモデル化可能です。 +***CPR***を設定すると、超電流位相関係の係数が変更されます。デフォルトは$I_S=I_C\sin(\phi)$に関連する1です。これを2に設定すると、この関係が$I_S = I_C\sin(2\phi)$に変更され、超電流の2次高調波のみを有効にして、最初の高調波を抑制することにより、$\pi$-junctionを使用できるようになります。[^1][^2] + ### Transmission Line {#transmission-line} @@ -461,3 +464,5 @@ JoSIMはビルトインの定数セットを持っており、展開された時 | EPS0 | $\epsilon_{0}$ | 8.854187817E-12 | | SIGMA | $\sigma$ (short for $\frac{\Phi_{0}}{2\pi}$) | 3.291059757E-16 | +[^1]:I. Salameh, E. G. Friedman and S. Kvatinsky, "Superconductive Logic Using 2ϕ—Josephson Junctions With Half Flux Quantum Pulses," in *IEEE Transactions on Circuits and Systems II: Express Briefs*, vol. 69, no. 5, pp. 2533-2537, May 2022, doi: 10.1109/TCSII.2022.3162723. +[^2]:S. V. Bakurskiy et al., "Current-phase relations in SIsFS junctions in the vicinity of 0-$\pi$ Transition", *Phys. Rev. B Condens. Matter*, vol. 95, pp. 94522-94528, Mar. 2017. diff --git a/docs/refer.bib b/docs/refer.bib index 2a739a05..be34310f 100644 --- a/docs/refer.bib +++ b/docs/refer.bib @@ -78,4 +78,29 @@ @article{haberkorn pages={K161--K164}, year={1978}, publisher={Wiley Online Library} -} \ No newline at end of file +} + +@ARTICLE{ebyCPR, + author={Salameh, Issa and Friedman, Eby G. and Kvatinsky, Shahar}, + journal={IEEE Transactions on Circuits and Systems II: Express Briefs}, + title={Superconductive Logic Using 2ϕ—Josephson Junctions With Half Flux Quantum Pulses}, + year={2022}, + volume={69}, + number={5}, + pages={2533-2537}, + doi={10.1109/TCSII.2022.3162723}} + +@article{bakyrskiyCPR, + title = {Current-phase relations in SIsFS junctions in the vicinity of 0-$\ensuremath{\pi}$ transition}, + author = {Bakurskiy, S. V. and Filippov, V. I. and Ruzhickiy, V. I. and Klenov, N. V. and Soloviev, I. I. and Kupriyanov, M. Yu. and Golubov, A. A.}, + journal = {Phys. Rev. B}, + volume = {95}, + issue = {9}, + pages = {094522}, + numpages = {11}, + year = {2017}, + month = {Mar}, + publisher = {American Physical Society}, + doi = {10.1103/PhysRevB.95.094522}, + url = {https://link.aps.org/doi/10.1103/PhysRevB.95.094522} +} diff --git a/docs/syntax.md b/docs/syntax.md index 61d8fb13..15e022fd 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -99,6 +99,7 @@ The only junction model currently supported by JoSIM is the RCSJ model and thus | D | 0.0, 1 | 0.0 | Point of contact transparency affecting current phase relationship | | ICFCT or ICFACT | 0, 1 | $\frac{\pi}{4}$ | Ratio of critical current to quasiparticle step height | | PHI | 0, $2\pi$ | 0 | Allows phi-junction capability such as the $\pi$-junction. | +| CPR | 0, $\infty$ | 1 | Sets the Current Phase Relationship constant. | The *.model* line is unique to the subcircuit it falls under and can thus allow different models with the same name under separate subcircuits. If the model is not found under the subcircuit it will be searched for globally and if not found default values (default model) will be used instead. @@ -106,6 +107,8 @@ The **AREA** and **IC** parameters act as modifiers to the model parameters. **A By setting the **PHI** parameter of the model, the phase value is persistantly subtracted from the phase ($\phi$) in the $\sin(\phi)$ part of the JJ current. This allows elements such as the $\pi$-junction to be modeled. +Setting **CPR** changes the coefficient of the supercurrent phase relationship. Default is 1 relating to $I_S=I_C\sin(\phi)$. Setting this to 2 would change this relationship to $I_S=I_C\sin(2\phi)$ which allows the use of $\pi$-junctions by enabling only the second harmonic of the supercurrent and suppressing the first.[^1][^2] + ### Transmission Line **T**Label $N^{+}_{1}$ $N^{-}_{1}$ $N^{+}_{2}$ $N^{-}_{2}$ **TD=VALUE** **Z0=VALUE** @@ -434,3 +437,5 @@ JoSIM has a set of built in constants that when used expand to the corresponding | EPS0 | $\epsilon_{0}$ | 8.854187817E-12 | | SIGMA | $\sigma$ (short for $\frac{\Phi_{0}}{2\pi}$) | 3.291059757E-16 | +[^1]: I. Salameh, E. G. Friedman and S. Kvatinsky, "Superconductive Logic Using 2ϕ—Josephson Junctions With Half Flux Quantum Pulses," in *IEEE Transactions on Circuits and Systems II: Express Briefs*, vol. 69, no. 5, pp. 2533-2537, May 2022, doi: 10.1109/TCSII.2022.3162723. +[^2]:S. V. Bakurskiy et al., "Current-phase relations in SIsFS junctions in the vicinity of 0-$\pi$ Transition", *Phys. Rev. B Condens. Matter*, vol. 95, pp. 94522-94528, Mar. 2017. diff --git a/include/JoSIM/AnalysisType.hpp b/include/JoSIM/AnalysisType.hpp index 69772cdc..e373b9c2 100644 --- a/include/JoSIM/AnalysisType.hpp +++ b/include/JoSIM/AnalysisType.hpp @@ -7,21 +7,19 @@ namespace JoSIM { - enum class AnalysisType : int64_t { - Voltage = 0, Phase = 1 - }; +enum class AnalysisType : int64_t { Voltage = 0, Phase = 1 }; - constexpr AnalysisType analysis_type_from_int(AnalysisType type) { - switch (type) { +constexpr AnalysisType analysis_type_from_int(AnalysisType type) { + switch (type) { case AnalysisType::Voltage: return AnalysisType::Voltage; case AnalysisType::Phase: return AnalysisType::Phase; default: throw std::runtime_error("Invalid analysis type"); - } } +} -} // namespace JoSIM +} // namespace JoSIM -#endif // JOSIM_ANALYSISTYPE_HPP +#endif // JOSIM_ANALYSISTYPE_HPP diff --git a/include/JoSIM/BasicComponent.hpp b/include/JoSIM/BasicComponent.hpp index d0c66b4b..a0c29071 100644 --- a/include/JoSIM/BasicComponent.hpp +++ b/include/JoSIM/BasicComponent.hpp @@ -3,75 +3,72 @@ #ifndef JOSIM_BASICCOMPONENT_H #define JOSIM_BASICCOMPONENT_H -#include "JoSIM/TypeDefines.hpp" -#include "JoSIM/Errors.hpp" - -#include -#include #include +#include +#include + +#include "JoSIM/Errors.hpp" +#include "JoSIM/TypeDefines.hpp" namespace JoSIM { - enum class NodeConfig { - GND = 0, POSGND = 1, GNDNEG = 2, POSNEG = 3 - }; - - using nodemap = std::unordered_map; - using nodeconnections = std::vector>>; - - class NetlistInfo { - public: - std::string label_; - double value_ = 0.0; - }; - - class IndexInfo { - public: - int_o posIndex_, negIndex_, currentIndex_; - NodeConfig nodeConfig_ = NodeConfig::GND; - }; - - class MatrixInfo { - public: - std::vector nonZeros_; - std::vector columnIndex_; - std::vector rowPointer_; - }; - - class BasicComponent { - public: - NetlistInfo netlistInfo; - IndexInfo indexInfo; - MatrixInfo matrixInfo; - - - void set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc) { - switch (indexInfo.nodeConfig_) { +enum class NodeConfig { GND = 0, POSGND = 1, GNDNEG = 2, POSNEG = 3 }; + +using nodemap = std::unordered_map; +using nodeconnections = std::vector>>; + +class NetlistInfo { + public: + std::string label_; + double value_ = 0.0; +}; + +class IndexInfo { + public: + int_o posIndex_, negIndex_, currentIndex_; + NodeConfig nodeConfig_ = NodeConfig::GND; +}; + +class MatrixInfo { + public: + std::vector nonZeros_; + std::vector columnIndex_; + std::vector rowPointer_; +}; + +class BasicComponent { + public: + NetlistInfo netlistInfo; + IndexInfo indexInfo; + MatrixInfo matrixInfo; + + void set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc) { + switch (indexInfo.nodeConfig_) { case NodeConfig::POSGND: indexInfo.posIndex_ = nm.at(t.at(0)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); break; case NodeConfig::GNDNEG: indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); break; case NodeConfig::POSNEG: indexInfo.posIndex_ = nm.at(t.at(0)); indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); break; case NodeConfig::GND: break; - } } + } - void set_matrix_info() { - switch (indexInfo.nodeConfig_) { + void set_matrix_info() { + switch (indexInfo.nodeConfig_) { case NodeConfig::POSGND: matrixInfo.nonZeros_.emplace_back(1); matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); @@ -92,27 +89,26 @@ namespace JoSIM { case NodeConfig::GND: matrixInfo.rowPointer_.emplace_back(1); break; - } - matrixInfo.columnIndex_.emplace_back(indexInfo.currentIndex_.value()); - sanity_check(); } - - void sanity_check() { - for (auto& i : matrixInfo.nonZeros_) { - if (i == 0 || std::isinf(i) || std::isnan(i)) { - Errors::matrix_errors( - MatrixErrors::SANITY_ERROR, netlistInfo.label_); - } + matrixInfo.columnIndex_.emplace_back(indexInfo.currentIndex_.value()); + sanity_check(); + } + + void sanity_check() { + for (auto& i : matrixInfo.nonZeros_) { + if (i == 0 || std::isinf(i) || std::isnan(i)) { + Errors::matrix_errors(MatrixErrors::SANITY_ERROR, netlistInfo.label_); } } + } - virtual void update_timestep(const double& factor) {}; + virtual void update_timestep(const double& factor){}; - virtual void step_back() {}; + virtual void step_back(){}; - virtual ~BasicComponent() {} + virtual ~BasicComponent() {} - }; // class BasicComponent +}; // class BasicComponent -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/CCCS.hpp b/include/JoSIM/CCCS.hpp index ae3de3c9..d30b648a 100644 --- a/include/JoSIM/CCCS.hpp +++ b/include/JoSIM/CCCS.hpp @@ -3,45 +3,44 @@ #ifndef JOSIM_CCCS_HPP #define JOSIM_CCCS_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Flabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G +/* + Flabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G - Io = GIc + Io = GIc - ⎡ 0 0 0 0 1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 -1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 1/G⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 -1/G⎟ ⎜Vc⁻⎟ ⎜ 0⎟ - ⎣ 0 0 1 -1 0⎦ ⎣Io ⎦ ⎣ 0⎦ - */ + ⎡ 0 0 0 0 1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 -1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 1/G⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 -1/G⎟ ⎜Vc⁻⎟ ⎜ 0⎟ + ⎣ 0 0 1 -1 0⎦ ⎣Io ⎦ ⎣ 0⎦ +*/ - class CCCS : public BasicComponent { - public: - NodeConfig nodeConfig2_; - int_o posIndex2_, negIndex2_; +class CCCS : public BasicComponent { + public: + NodeConfig nodeConfig2_; + int_o posIndex2_, negIndex2_; - CCCS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi); + CCCS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi); - void set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc); - void set_matrix_info(); - }; // class CCCS + void set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc); + void set_matrix_info(); +}; // class CCCS -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/CCVS.hpp b/include/JoSIM/CCVS.hpp index e086c6f0..676fac69 100644 --- a/include/JoSIM/CCVS.hpp +++ b/include/JoSIM/CCVS.hpp @@ -3,69 +3,68 @@ #ifndef JOSIM_CCVS_HPP #define JOSIM_CCVS_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/Input.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Hlabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G - - Vo = GIc - - ⎡ 0 0 0 0 0 1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 0 -1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 1 0⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 -1 0⎟ ⎜Vc⁻⎟ ⎜ 0⎟ - ⎜ 1 -1 0 0 -G 0⎟ ⎜Ic ⎟ ⎜ 0⎟ - ⎣ 0 0 1 -1 0 0⎦ ⎣Io ⎦ ⎣ 0⎦ - - (PHASE) - φ - (2e/hbar)(2h/3G)Ic = (4/3)φn-1 - (1/3)φn-2 - - ⎡ 0 0 0 0 0 1⎤ ⎡φo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 0 -1⎟ ⎜φo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 1 0⎟ ⎜φc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 -1 0⎟ ⎜φc⁻⎟ ⎜ 0⎟ - ⎜ 1 -1 0 0 -(2e/hbar)(2h/3G) 0⎟ ⎜Ic ⎟ ⎜ (4/3)φn-1 - (1/3)φn-2⎟ - ⎣ 0 0 1 -1 0 0⎦ ⎣Io ⎦ ⎣ 0⎦ - */ - - class CCVS : public BasicComponent { - private: - int64_t hDepPos_ = 0; - JoSIM::AnalysisType at_; - public: - NodeConfig nodeConfig2_; - int_o posIndex2_, negIndex2_; - int64_t currentIndex2_ = 0; - double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0; - - CCVS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi, const AnalysisType& at, const double& h); - - void set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc); - void set_matrix_info(const AnalysisType& at, const double& h); - - void update_timestep(const double& factor) override; - - void step_back() override { - pn2_ = pn4_; - } - - }; // class CCVS - -} // namespace JoSIM +/* + Hlabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G + + Vo = GIc + + ⎡ 0 0 0 0 0 1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 0 -1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 1 0⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 -1 0⎟ ⎜Vc⁻⎟ ⎜ 0⎟ + ⎜ 1 -1 0 0 -G 0⎟ ⎜Ic ⎟ ⎜ 0⎟ + ⎣ 0 0 1 -1 0 0⎦ ⎣Io ⎦ ⎣ 0⎦ + + (PHASE) + φ - (2e/hbar)(2h/3G)Ic = (4/3)φn-1 - (1/3)φn-2 + + ⎡ 0 0 0 0 0 1⎤ ⎡φo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 0 -1⎟ ⎜φo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 1 0⎟ ⎜φc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 -1 0⎟ ⎜φc⁻⎟ ⎜ 0⎟ + ⎜ 1 -1 0 0 -(2e/hbar)(2h/3G) 0⎟ ⎜Ic ⎟ ⎜ (4/3)φn-1 - (1/3)φn-2⎟ + ⎣ 0 0 1 -1 0 0⎦ ⎣Io ⎦ ⎣ 0⎦ +*/ + +class CCVS : public BasicComponent { + private: + int64_t hDepPos_ = 0; + JoSIM::AnalysisType at_; + + public: + NodeConfig nodeConfig2_; + int_o posIndex2_, negIndex2_; + int64_t currentIndex2_ = 0; + double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0; + + CCVS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi, const AnalysisType& at, + const double& h); + + void set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc); + void set_matrix_info(const AnalysisType& at, const double& h); + + void update_timestep(const double& factor) override; + + void step_back() override { pn2_ = pn4_; } + +}; // class CCVS + +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Capacitor.hpp b/include/JoSIM/Capacitor.hpp index 4db83a76..f46eae75 100644 --- a/include/JoSIM/Capacitor.hpp +++ b/include/JoSIM/Capacitor.hpp @@ -3,59 +3,59 @@ #ifndef JOSIM_CAPACITOR_HPP #define JOSIM_CAPACITOR_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/Input.hpp" #include "JoSIM/Spread.hpp" -#include -#include -#include -#include - namespace JoSIM { - /* - Clabel V⁺ V⁻ C +/* + Clabel V⁺ V⁻ C + + V - (2*h)/(3*C)Io = (4/3)Vn-1 - (1/3)Vn-2 - V - (2*h)/(3*C)Io = (4/3)Vn-1 - (1/3)Vn-2 + ⎡ 0 0 1⎤ ⎡ V⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜ V⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 -(2*h)/(3*C)⎦ ⎣Io ⎦ ⎣ (4/3)Vn-1 - (1/3)Vn-2⎦ - ⎡ 0 0 1⎤ ⎡ V⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜ V⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 -(2*h)/(3*C)⎦ ⎣Io ⎦ ⎣ (4/3)Vn-1 - (1/3)Vn-2⎦ + (PHASE) + φ - (4*h*h*2*e)/(hbar*9*C)Io = + (8/3)φn-1 - (22/9)φn-2 + (8/9)φn-3 - (1/9)φn-4 - (PHASE) - φ - (4*h*h*2*e)/(hbar*9*C)Io = - (8/3)φn-1 - (22/9)φn-2 + (8/9)φn-3 - (1/9)φn-4 + ⎡ 0 0 1⎤ ⎡ φ⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜ φ⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 -(4*h*h*2*e)/(hbar*9*C)⎦ ⎣Io ⎦ ⎣ RHS⎦ - ⎡ 0 0 1⎤ ⎡ φ⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜ φ⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 -(4*h*h*2*e)/(hbar*9*C)⎦ ⎣Io ⎦ ⎣ RHS⎦ + RHS = (8/3)φn-1 - (22/9)φn-2 + (8/9)φn-3 - (1/9)φn-4 +*/ - RHS = (8/3)φn-1 - (22/9)φn-2 + (8/9)φn-3 - (1/9)φn-4 - */ +class Capacitor : public BasicComponent { + private: + JoSIM::AnalysisType at_; - class Capacitor : public BasicComponent { - private: - JoSIM::AnalysisType at_; - public: - double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, - pn4_ = 0.0, pn5_ = 0.0, pn6_ = 0.0, pn7_ = 0.0; - Capacitor( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi); + public: + double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0, pn5_ = 0.0, pn6_ = 0.0, + pn7_ = 0.0; + Capacitor(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi); - void update_timestep(const double& factor) override; + void update_timestep(const double& factor) override; - void step_back() override { - pn4_ = pn7_; - pn3_ = pn6_; - pn2_ = pn5_; - } - }; // class Capacitor + void step_back() override { + pn4_ = pn7_; + pn3_ = pn6_; + pn2_ = pn5_; + } +}; // class Capacitor -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/CliOptions.hpp b/include/JoSIM/CliOptions.hpp index 47429da9..b387962c 100644 --- a/include/JoSIM/CliOptions.hpp +++ b/include/JoSIM/CliOptions.hpp @@ -3,40 +3,38 @@ #ifndef JOSIM_CLIOPTIONS_HPP #define JOSIM_CLIOPTIONS_HPP +#include +#include +#include + #include "JoSIM/AnalysisType.hpp" #include "JoSIM/FileOutputType.hpp" #include "JoSIM/TypeDefines.hpp" -#include -#include -#include - namespace JoSIM { - struct CliOptions { - private: - - tokens_t argv_to_tokens(const int64_t& argc, const char** argv); - vector_pair_t argument_pairs(const tokens_t& tokens); - - public: +struct CliOptions { + private: + tokens_t argv_to_tokens(const int64_t& argc, const char** argv); + vector_pair_t argument_pairs(const tokens_t& tokens); - string_o cir_file_name; - std::optional output_file; + public: + string_o cir_file_name; + std::optional output_file; - AnalysisType analysis_type = AnalysisType::Phase; + AnalysisType analysis_type = AnalysisType::Phase; - int64_t verbose = 0; - bool SLU = false; - bool minimal = false; - bool parallel = false; + int64_t verbose = 0; + bool SLU = false; + bool minimal = false; + bool parallel = false; - // helper functions - static CliOptions parse(int64_t argc, const char** argv); - static void display_help(); - static void version_info(); - }; + // helper functions + static CliOptions parse(int64_t argc, const char** argv); + static void display_help(); + static void version_info(); +}; -} // namespace JoSIM +} // namespace JoSIM -#endif // JOSIM_CLIOPTIONS_HPP +#endif // JOSIM_CLIOPTIONS_HPP diff --git a/include/JoSIM/Components.hpp b/include/JoSIM/Components.hpp index 6c6c83a5..1c561309 100644 --- a/include/JoSIM/Components.hpp +++ b/include/JoSIM/Components.hpp @@ -3,54 +3,39 @@ #ifndef JOSIM_COMPONENTS_HPP #define JOSIM_COMPONENTS_HPP -#include "JoSIM/Misc.hpp" -#include "JoSIM/Parameters.hpp" +#include + +#include "JoSIM/CCCS.hpp" +#include "JoSIM/CCVS.hpp" +#include "JoSIM/Capacitor.hpp" #include "JoSIM/Constants.hpp" -#include "JoSIM/Input.hpp" +#include "JoSIM/CurrentSource.hpp" #include "JoSIM/Errors.hpp" -#include "JoSIM/Resistor.hpp" #include "JoSIM/Inductor.hpp" -#include "JoSIM/Capacitor.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/JJ.hpp" -#include "JoSIM/VoltageSource.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/Parameters.hpp" #include "JoSIM/PhaseSource.hpp" -#include "JoSIM/CurrentSource.hpp" +#include "JoSIM/Resistor.hpp" #include "JoSIM/TransmissionLine.hpp" #include "JoSIM/VCCS.hpp" -#include "JoSIM/CCCS.hpp" #include "JoSIM/VCVS.hpp" -#include "JoSIM/CCVS.hpp" - -#include +#include "JoSIM/VoltageSource.hpp" namespace JoSIM { - class Components { - public: - std::vector> devices; - std::vector currentsources; - std::vector junctionIndices, - resistorIndices, - inductorIndices, - capacitorIndices, - vsIndices, - psIndices, - txIndices, - vccsIndices, - cccsIndices, - vcvsIndices, - ccvsIndices; - std::vector> mutualinductances; - }; // class Components +class Components { + public: + std::vector< + std::variant> + devices; + std::vector currentsources; + std::vector junctionIndices, resistorIndices, inductorIndices, + capacitorIndices, vsIndices, psIndices, txIndices, vccsIndices, + cccsIndices, vcvsIndices, ccvsIndices; + std::vector> mutualinductances; +}; // class Components -} // namespace JoSIM +} // namespace JoSIM #endif diff --git a/include/JoSIM/Constants.hpp b/include/JoSIM/Constants.hpp index 691ddaff..ae6c0339 100644 --- a/include/JoSIM/Constants.hpp +++ b/include/JoSIM/Constants.hpp @@ -6,18 +6,18 @@ #include namespace JoSIM { - namespace Constants { - static constexpr double PI = 3.141592653589793238463; - static constexpr double PHI_ZERO = 2.067833831170082E-15; - static constexpr double BOLTZMANN = 1.38064852E-23; - static constexpr double EV = 1.6021766208e-19; - static constexpr double HBAR = 1.0545718001391127e-34; - static constexpr double C = 299792458; - static constexpr double MU0 = 12.566370614E-7; - static constexpr double EPS0 = 8.854187817E-12; - // HBAR / 2 * EV - static constexpr double SIGMA = 3.291059757e-16; - } -} +namespace Constants { +static constexpr double PI = 3.141592653589793238463; +static constexpr double PHI_ZERO = 2.067833831170082E-15; +static constexpr double BOLTZMANN = 1.38064852E-23; +static constexpr double EV = 1.6021766208e-19; +static constexpr double HBAR = 1.0545718001391127e-34; +static constexpr double C = 299792458; +static constexpr double MU0 = 12.566370614E-7; +static constexpr double EPS0 = 8.854187817E-12; +// HBAR / 2 * EV +static constexpr double SIGMA = 3.291059757e-16; +} // namespace Constants +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/CurrentSource.hpp b/include/JoSIM/CurrentSource.hpp index 6dc57d47..85e4e0de 100644 --- a/include/JoSIM/CurrentSource.hpp +++ b/include/JoSIM/CurrentSource.hpp @@ -3,32 +3,32 @@ #ifndef JOSIM_CURRENTSOURCE_HPP #define JOSIM_CURRENTSOURCE_HPP -#include "JoSIM/BasicComponent.hpp" - #include +#include #include #include -#include + +#include "JoSIM/BasicComponent.hpp" namespace JoSIM { - /* - Ilabel V⁺ V⁻ sourcetype +/* + Ilabel V⁺ V⁻ sourcetype - ⎡ 0 0⎤ ⎡ V⁺⎤ = ⎡ Io⎤ - ⎣ 0 0⎦ ⎣ V⁻⎦ ⎣ -Io⎦ - */ + ⎡ 0 0⎤ ⎡ V⁺⎤ = ⎡ Io⎤ + ⎣ 0 0⎦ ⎣ V⁻⎦ ⎣ -Io⎦ +*/ - class CurrentSource : public BasicComponent { - public: - int64_t sourceIndex_; +class CurrentSource : public BasicComponent { + public: + int64_t sourceIndex_; - CurrentSource( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, const int64_t& si); + CurrentSource(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + const int64_t& si); - void set_node_indices(const tokens_t& t, const nodemap& nm); - }; // class CurrentSource + void set_node_indices(const tokens_t& t, const nodemap& nm); +}; // class CurrentSource -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Errors.hpp b/include/JoSIM/Errors.hpp index 5f9b12f8..9e171d84 100644 --- a/include/JoSIM/Errors.hpp +++ b/include/JoSIM/Errors.hpp @@ -3,225 +3,210 @@ #ifndef JOSIM_ERRORS_HPP #define JOSIM_ERRORS_HPP -#include "JoSIM/TypeDefines.hpp" - #include +#include "JoSIM/TypeDefines.hpp" + namespace JoSIM { - enum class CLIErrors : int64_t { - NO_ANALYSIS, - NO_SOLVER, - NO_INTEGRATION, - NO_CONVENTION, - NO_OUTPUT, - NO_INPUT, - UNKNOWN_SWITCH, - UNKNOWN_OUTPUT_TYPE, - TOO_FEW_ARGUMENTS, - INVALID_ANALYSIS, - INVALID_SOLVER, - INVALID_INTEGRATION, - INVALID_CONVENTION, - INVALID_MINIMAL, - INPUT_SAME_OUTPUT - }; - - enum class InputErrors : int64_t { - CANNOT_OPEN_FILE, - CYCLIC_INCLUDE, - MISSING_SUBCKT_IO, - MISSING_SUBCKT_NAME, - SUBCKT_CONTROLS, - MISSING_MAIN, - UNKNOWN_SUBCKT, - EMPTY_FILE, - IO_MISMATCH, - UNKNOWN_CONTROL - }; - - enum class ComponentErrors : int64_t { - INVALID_COMPONENT_DECLARATION, - BOTH_GROUND, - GROUNDED_VOLTAGE_SOURCE, - CAP_ERROR, - IND_ERROR, - RES_ERROR, - JJ_ERROR, - KMUT_ERROR, - IS_ERROR, - VS_ERROR, - TRL_ERROR, - LABEL_ERROR, - MISSING_LABEL, - MISSING_PNODE, - MISSING_NNODE, - MISSING_JJMODEL, - MODEL_NOT_DEFINED, - MODEL_AREA_NOT_GIVEN, - DUPLICATE_LABEL, - INVALID_SUBCIRCUIT_NODES, - TIME_ERROR, - MISSING_SUBCIRCUIT_NAME, - MUT_ERROR, - INVALID_EXPR, - INVALID_TX_DEFINED, - INVALID_TX_RESOLUTION, - MISSING_INDUCTOR, - UNKNOWN_DEVICE_TYPE, - SPECIAL_CHARS - }; - - enum class ControlErrors : int64_t { - TRANS_ERROR, - PRINT_ERROR, - PLOT_ERROR, - INV_CONTROL, - DC_ERROR, - AC_ERROR, - PHASE_ERROR, - NO_SIM, - PRINT_TOO_MANY_ARGS, - UNKNOWN_DEVICE, - CURRENT_THROUGH_VOLT, - VOLT_WHEN_PHASE, - VOLT_ACROSS_CURRENT, - NODEVOLT_WHEN_PHASE, - UNKNOWN_NODE, - INVALID_NODEV, - NODEPHASE_WHEN_VOLT, - INVALID_NODEP, - PHASE_WHEN_VOLT, - PHASE_OF_VOLT, - PHASE_OF_CURRENT, - INVALID_CURRENT, - MATHOPS, - UNKNOWN_PLOT, - INVALID_OUTPUT_COMMAND, - INVALID_FILE_COMMAND, - INVALID_IV_COMMAND, - IV_MODEL_NOT_FOUND, - NODECURRENT - }; - - enum class ModelErrors : int64_t { - PARAM_TYPE_ERROR, - UNKNOWN_MODEL_TYPE, - BAD_MODEL_DEFINITION - }; - - enum class MatrixErrors : int64_t { - NON_SQUARE, - SANITY_ERROR - }; - - enum class MiscErrors : int64_t { - STOD_ERROR - }; - - enum class FunctionErrors : int64_t { - INITIAL_VALUES, - TOO_FEW_TIMESTEPS, - TOO_FEW_VALUES, - INITIAL_PULSE_VALUE, - PULSE_TOO_FEW_ARGUMENTS, - PULSE_VPEAK_ZERO, - PULSE_RISE_TIME_ZERO, - PULSE_FALL_TIME_ZERO, - PULSE_WIDTH_ZERO, - PULSE_REPEAT, - SIN_TOO_FEW_ARGUMENTS, - SIN_TOO_MANY_ARGUMENTS, - SIN_VA_ZERO, - CUS_TOO_FEW_ARGUMENTS, - CUS_TOO_MANY_ARGUMENTS, - CUS_SF_ZERO, - CUS_WF_NOT_FOUND, - CUS_UNKNOWN_IM, - NOISE_TOO_FEW_ARGUMENTS, - NOISE_TOO_MANY_ARGUMENTS, - NOISE_VA_ZERO, - NOISE_VO_ZERO, - EXP_TOO_FEW_ARGUMENTS - }; - - enum class SimulationErrors : int64_t { - JJCAP_NOT_FOUND, - JJICRIT_NOT_FOUND, - JJPHASE_NODE_NOT_FOUND, - INDUCTOR_CURRENT_NOT_FOUND, - MATRIX_SINGULAR, - PHASEGUESS_TOO_LARGE - }; - - enum class ParsingErrors : int64_t { - EXPRESSION_ARLEADY_DEFINED, - UNIDENTIFIED_PART, - MISMATCHED_PARENTHESIS, - INVALID_RPN, - INVALID_DECLARATION - }; - - enum class OutputErrors : int64_t { - CANNOT_OPEN_FILE, - NOTHING_SPECIFIED - }; - - enum class NetlistErrors : int64_t { - NO_SUCH_NODE, - MISSING_IO - }; - - enum class VerbosityErrors : int64_t { - NO_SUCH_LEVEL, - INVALID_VERBOSITY_LEVEL - }; - - class Errors { - public: - static void cli_errors( - CLIErrors errorCode, string_o message = std::nullopt); - - static void input_errors( - InputErrors errorCode, string_o message = std::nullopt); - - static void invalid_component_errors( - ComponentErrors errorCode, string_o componentLabel = std::nullopt); - - static void control_errors( - ControlErrors errorCode, string_o message = std::nullopt); - - static void model_errors( - ModelErrors errorCode, string_o message = std::nullopt); - - [[noreturn]] static void matrix_errors( - MatrixErrors errorCode, string_o message = std::nullopt); - - [[noreturn]] static void misc_errors( - MiscErrors errorCode, string_o message = std::nullopt); - - static void function_errors( - FunctionErrors errorCode, string_o message = std::nullopt); - - [[noreturn]] static void simulation_errors( - SimulationErrors errorCode, string_o message = std::nullopt); - - static void parsing_errors( - ParsingErrors errorCode, string_o message = std::nullopt); - - static void output_errors( - OutputErrors errorCode, string_o message = std::nullopt); - - [[noreturn]] static void netlist_errors( - NetlistErrors errorCode, string_o message = std::nullopt); - - static void verbosity_errors( - VerbosityErrors errorCode, string_o message = std::nullopt); - - [[noreturn]] static void oor(); - - [[noreturn]] static void error_message(const std::string& formattedMessage); - - static void warning_message(const std::string& formattedMessage); - }; -} // namespace JoSIM +enum class CLIErrors : int64_t { + NO_ANALYSIS, + NO_SOLVER, + NO_INTEGRATION, + NO_CONVENTION, + NO_OUTPUT, + NO_INPUT, + UNKNOWN_SWITCH, + UNKNOWN_OUTPUT_TYPE, + TOO_FEW_ARGUMENTS, + INVALID_ANALYSIS, + INVALID_SOLVER, + INVALID_INTEGRATION, + INVALID_CONVENTION, + INVALID_MINIMAL, + INPUT_SAME_OUTPUT +}; + +enum class InputErrors : int64_t { + CANNOT_OPEN_FILE, + CYCLIC_INCLUDE, + MISSING_SUBCKT_IO, + MISSING_SUBCKT_NAME, + SUBCKT_CONTROLS, + MISSING_MAIN, + UNKNOWN_SUBCKT, + EMPTY_FILE, + IO_MISMATCH, + UNKNOWN_CONTROL +}; + +enum class ComponentErrors : int64_t { + INVALID_COMPONENT_DECLARATION, + BOTH_GROUND, + GROUNDED_VOLTAGE_SOURCE, + CAP_ERROR, + IND_ERROR, + RES_ERROR, + JJ_ERROR, + KMUT_ERROR, + IS_ERROR, + VS_ERROR, + TRL_ERROR, + LABEL_ERROR, + MISSING_LABEL, + MISSING_PNODE, + MISSING_NNODE, + MISSING_JJMODEL, + MODEL_NOT_DEFINED, + MODEL_AREA_NOT_GIVEN, + DUPLICATE_LABEL, + INVALID_SUBCIRCUIT_NODES, + TIME_ERROR, + MISSING_SUBCIRCUIT_NAME, + MUT_ERROR, + INVALID_EXPR, + INVALID_TX_DEFINED, + INVALID_TX_RESOLUTION, + MISSING_INDUCTOR, + UNKNOWN_DEVICE_TYPE, + SPECIAL_CHARS +}; + +enum class ControlErrors : int64_t { + TRANS_ERROR, + PRINT_ERROR, + PLOT_ERROR, + INV_CONTROL, + DC_ERROR, + AC_ERROR, + PHASE_ERROR, + NO_SIM, + PRINT_TOO_MANY_ARGS, + UNKNOWN_DEVICE, + CURRENT_THROUGH_VOLT, + VOLT_WHEN_PHASE, + VOLT_ACROSS_CURRENT, + NODEVOLT_WHEN_PHASE, + UNKNOWN_NODE, + INVALID_NODEV, + NODEPHASE_WHEN_VOLT, + INVALID_NODEP, + PHASE_WHEN_VOLT, + PHASE_OF_VOLT, + PHASE_OF_CURRENT, + INVALID_CURRENT, + MATHOPS, + UNKNOWN_PLOT, + INVALID_OUTPUT_COMMAND, + INVALID_FILE_COMMAND, + INVALID_IV_COMMAND, + IV_MODEL_NOT_FOUND, + NODECURRENT +}; + +enum class ModelErrors : int64_t { + PARAM_TYPE_ERROR, + UNKNOWN_MODEL_TYPE, + BAD_MODEL_DEFINITION +}; + +enum class MatrixErrors : int64_t { NON_SQUARE, SANITY_ERROR }; + +enum class MiscErrors : int64_t { STOD_ERROR }; + +enum class FunctionErrors : int64_t { + INITIAL_VALUES, + TOO_FEW_TIMESTEPS, + TOO_FEW_VALUES, + INITIAL_PULSE_VALUE, + PULSE_TOO_FEW_ARGUMENTS, + PULSE_VPEAK_ZERO, + PULSE_RISE_TIME_ZERO, + PULSE_FALL_TIME_ZERO, + PULSE_WIDTH_ZERO, + PULSE_REPEAT, + SIN_TOO_FEW_ARGUMENTS, + SIN_TOO_MANY_ARGUMENTS, + SIN_VA_ZERO, + CUS_TOO_FEW_ARGUMENTS, + CUS_TOO_MANY_ARGUMENTS, + CUS_SF_ZERO, + CUS_WF_NOT_FOUND, + CUS_UNKNOWN_IM, + NOISE_TOO_FEW_ARGUMENTS, + NOISE_TOO_MANY_ARGUMENTS, + NOISE_VA_ZERO, + NOISE_VO_ZERO, + EXP_TOO_FEW_ARGUMENTS +}; + +enum class SimulationErrors : int64_t { + JJCAP_NOT_FOUND, + JJICRIT_NOT_FOUND, + JJPHASE_NODE_NOT_FOUND, + INDUCTOR_CURRENT_NOT_FOUND, + MATRIX_SINGULAR, + PHASEGUESS_TOO_LARGE +}; + +enum class ParsingErrors : int64_t { + EXPRESSION_ARLEADY_DEFINED, + UNIDENTIFIED_PART, + MISMATCHED_PARENTHESIS, + INVALID_RPN, + INVALID_DECLARATION +}; + +enum class OutputErrors : int64_t { CANNOT_OPEN_FILE, NOTHING_SPECIFIED }; + +enum class NetlistErrors : int64_t { NO_SUCH_NODE, MISSING_IO }; + +enum class VerbosityErrors : int64_t { NO_SUCH_LEVEL, INVALID_VERBOSITY_LEVEL }; + +class Errors { + public: + static void cli_errors(CLIErrors errorCode, string_o message = std::nullopt); + + static void input_errors(InputErrors errorCode, + string_o message = std::nullopt); + + static void invalid_component_errors(ComponentErrors errorCode, + string_o componentLabel = std::nullopt); + + static void control_errors(ControlErrors errorCode, + string_o message = std::nullopt); + + static void model_errors(ModelErrors errorCode, + string_o message = std::nullopt); + + [[noreturn]] static void matrix_errors(MatrixErrors errorCode, + string_o message = std::nullopt); + + [[noreturn]] static void misc_errors(MiscErrors errorCode, + string_o message = std::nullopt); + + static void function_errors(FunctionErrors errorCode, + string_o message = std::nullopt); + + [[noreturn]] static void simulation_errors(SimulationErrors errorCode, + string_o message = std::nullopt); + + static void parsing_errors(ParsingErrors errorCode, + string_o message = std::nullopt); + + static void output_errors(OutputErrors errorCode, + string_o message = std::nullopt); + + [[noreturn]] static void netlist_errors(NetlistErrors errorCode, + string_o message = std::nullopt); + + static void verbosity_errors(VerbosityErrors errorCode, + string_o message = std::nullopt); + + [[noreturn]] static void oor(); + + [[noreturn]] static void error_message(const std::string& formattedMessage); + + static void warning_message(const std::string& formattedMessage); +}; +} // namespace JoSIM #endif diff --git a/include/JoSIM/FileOutputType.hpp b/include/JoSIM/FileOutputType.hpp index e2838d6e..3c7c6c20 100644 --- a/include/JoSIM/FileOutputType.hpp +++ b/include/JoSIM/FileOutputType.hpp @@ -3,54 +3,47 @@ #ifndef JOSIM_FILEOUTPUTTYPE_HPP #define JOSIM_FILEOUTPUTTYPE_HPP -#include "JoSIM/Errors.hpp" - -#include #include +#include + +#include "JoSIM/Errors.hpp" namespace JoSIM { - enum class FileOutputType { - Csv = 0, Dat = 1, Raw = 2 - }; +enum class FileOutputType { Csv = 0, Dat = 1, Raw = 2 }; - class OutputFile { - private: - FileOutputType type_ = FileOutputType::Csv; - std::string name_; - public: - OutputFile() {}; - OutputFile(std::string value) { - name(value); - type(value); - }; - std::string name() { - return name_; - } - void name(std::string value) { - name_ = value; - } - FileOutputType type() { - return type_; - } - void type(std::string value) { - std::string ext = std::filesystem::path(value).extension().string(); - std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper); - if (ext.empty()) { - type_ = FileOutputType::Raw; - } else if (ext == ".CSV") { - type_ = FileOutputType::Csv; - } else if (ext == ".DAT") { - type_ = FileOutputType::Dat; - } else if (ext == ".RAW") { - type_ = FileOutputType::Raw; - } else { - Errors::cli_errors(CLIErrors::UNKNOWN_OUTPUT_TYPE, ext); - type_ = FileOutputType::Csv; - } - } +class OutputFile { + private: + FileOutputType type_ = FileOutputType::Csv; + std::string name_; + + public: + OutputFile(){}; + OutputFile(std::string value) { + name(value); + type(value); }; + std::string name() { return name_; } + void name(std::string value) { name_ = value; } + FileOutputType type() { return type_; } + void type(std::string value) { + std::string ext = std::filesystem::path(value).extension().string(); + std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper); + if (ext.empty()) { + type_ = FileOutputType::Raw; + } else if (ext == ".CSV") { + type_ = FileOutputType::Csv; + } else if (ext == ".DAT") { + type_ = FileOutputType::Dat; + } else if (ext == ".RAW") { + type_ = FileOutputType::Raw; + } else { + Errors::cli_errors(CLIErrors::UNKNOWN_OUTPUT_TYPE, ext); + type_ = FileOutputType::Csv; + } + } +}; -} // namespace JoSIM +} // namespace JoSIM -#endif // JOSIM_FILEOUTPUTTYPE_HPP +#endif // JOSIM_FILEOUTPUTTYPE_HPP diff --git a/include/JoSIM/Function.hpp b/include/JoSIM/Function.hpp index 5527487f..8a5ab448 100644 --- a/include/JoSIM/Function.hpp +++ b/include/JoSIM/Function.hpp @@ -3,59 +3,56 @@ #ifndef JOSIM_FUNCTION_HPP #define JOSIM_FUNCTION_HPP -#include "Input.hpp" - #include +#include "Input.hpp" + namespace JoSIM { - enum class FunctionType { - PWL = 0, - PULSE = 1, - SINUSOID = 2, - CUS = 3, - NOISE = 4, - PWS = 5, - DC = 6, - EXP = 7 - }; - - class Function { - private: - FunctionType fType_ = FunctionType::PWL; - std::vector timeValues_; - std::vector ampValues_; - std::vector miscValues_; - void parse_pwl(const tokens_t& t, const Input& iObj, const string_o& s); - void parse_pulse(const tokens_t& t, const Input& iObj, const string_o& s); - void parse_sin(const tokens_t& t, const Input& iObj, const string_o& s); - void parse_cus(const tokens_t& t, const Input& iObj, const string_o& s); - void parse_noise(const tokens_t& t, const Input& iObj, const string_o& s); - void parse_dc(const tokens_t& t, const Input& iObj, const string_o& s); - void parse_exp(const tokens_t& t, const Input& iObj, const string_o& s); - double return_pwl(double& x); - double return_pulse(double& x); - double return_sin(double& x); - double return_cus(double& x); - double return_noise(double& x); - double return_pws(double& x); - double return_dc(); - double return_exp(double& x); - public: - Function() {}; - void parse_function(const std::string& str, const Input& iObj, - const string_o& subckt); - double value(double x); - void ampValues(std::vector values); - std::vector ampValues() { - return ampValues_; - } - void clearMisc() { - miscValues_.clear(); - } - - }; // class Function - -} // namespace JoSIM - -#endif // JOSIM_FUNCTION_HPP +enum class FunctionType { + PWL = 0, + PULSE = 1, + SINUSOID = 2, + CUS = 3, + NOISE = 4, + PWS = 5, + DC = 6, + EXP = 7 +}; + +class Function { + private: + FunctionType fType_ = FunctionType::PWL; + std::vector timeValues_; + std::vector ampValues_; + std::vector miscValues_; + void parse_pwl(const tokens_t& t, const Input& iObj, const string_o& s); + void parse_pulse(const tokens_t& t, const Input& iObj, const string_o& s); + void parse_sin(const tokens_t& t, const Input& iObj, const string_o& s); + void parse_cus(const tokens_t& t, const Input& iObj, const string_o& s); + void parse_noise(const tokens_t& t, const Input& iObj, const string_o& s); + void parse_dc(const tokens_t& t, const Input& iObj, const string_o& s); + void parse_exp(const tokens_t& t, const Input& iObj, const string_o& s); + double return_pwl(double& x); + double return_pulse(double& x); + double return_sin(double& x); + double return_cus(double& x); + double return_noise(double& x); + double return_pws(double& x); + double return_dc(); + double return_exp(double& x); + + public: + Function(){}; + void parse_function(const std::string& str, const Input& iObj, + const string_o& subckt); + double value(double x); + void ampValues(std::vector values); + std::vector ampValues() { return ampValues_; } + void clearMisc() { miscValues_.clear(); } + +}; // class Function + +} // namespace JoSIM + +#endif // JOSIM_FUNCTION_HPP diff --git a/include/JoSIM/IV.hpp b/include/JoSIM/IV.hpp index 3fac676b..8b6e284f 100644 --- a/include/JoSIM/IV.hpp +++ b/include/JoSIM/IV.hpp @@ -5,22 +5,21 @@ #include "Input.hpp" #include "Matrix.hpp" -#include "Simulation.hpp" #include "Model.hpp" +#include "Simulation.hpp" namespace JoSIM { - class IV { - public: - IV(const Input iObj); - void setup_iv(const tokens_t& i, const Input& iObj); - std::vector> generate_iv(double maxC, - Input ivInp); - std::pair do_simulate(Input& ivInp, Matrix& ivMat); - void write_iv(std::vector>& iv_data, - const std::string& output_path); - }; +class IV { + public: + IV(const Input iObj); + void setup_iv(const tokens_t& i, const Input& iObj); + std::vector> generate_iv(double maxC, Input ivInp); + std::pair do_simulate(Input& ivInp, Matrix& ivMat); + void write_iv(std::vector>& iv_data, + const std::string& output_path); +}; -} // namespace JoSIM +} // namespace JoSIM -#endif // JOSIM_IV_HPP +#endif // JOSIM_IV_HPP diff --git a/include/JoSIM/Inductor.hpp b/include/JoSIM/Inductor.hpp index 715da772..a08fe091 100644 --- a/include/JoSIM/Inductor.hpp +++ b/include/JoSIM/Inductor.hpp @@ -3,67 +3,64 @@ #ifndef JOSIM_INDUCTOR_HPP #define JOSIM_INDUCTOR_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/Input.hpp" #include "JoSIM/Spread.hpp" -#include -#include -#include -#include - - namespace JoSIM { - /* - Llabel V⁺ V⁻ L +/* + Llabel V⁺ V⁻ L + + V - (3*L)/(2*h)Io = -(2*L)/(h)In-1 + (L)/(2*h)In-2 - V - (3*L)/(2*h)Io = -(2*L)/(h)In-1 + (L)/(2*h)In-2 + ⎡ 0 0 1⎤ ⎡V⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜V⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 -(3*L)/(2*h)⎦ ⎣Io⎦ ⎣ -(2*L)/(h)In-1 + (L)/(2*h)In-2⎦ - ⎡ 0 0 1⎤ ⎡V⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜V⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 -(3*L)/(2*h)⎦ ⎣Io⎦ ⎣ -(2*L)/(h)In-1 + (L)/(2*h)In-2⎦ + (PHASE) + φ - L(2e/hbar)Io = 0 - (PHASE) - φ - L(2e/hbar)Io = 0 + ⎡ 0 0 1⎤ ⎡φ⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜φ⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 -L(2e/hbar)⎦ ⎣Io⎦ ⎣ 0⎦ +*/ - ⎡ 0 0 1⎤ ⎡φ⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜φ⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 -L(2e/hbar)⎦ ⎣Io⎦ ⎣ 0⎦ - */ +using mutualinductors = std::vector>; - using mutualinductors = std::vector>; +class Inductor : public BasicComponent { + private: + JoSIM::AnalysisType at_; - class Inductor : public BasicComponent { - private: - JoSIM::AnalysisType at_; - public: - double In2_ = 0.0, In3_ = 0.0, In4_ = 0.0; - mutualinductors mutualInductances_; + public: + double In2_ = 0.0, In3_ = 0.0, In4_ = 0.0; + mutualinductors mutualInductances_; - Inductor( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, Input& iObj, Spread spread, int64_t& bi); + Inductor(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, Input& iObj, Spread spread, int64_t& bi); - void set_mutualInductance(const std::pair& mut) { - mutualInductances_.emplace_back(mut); - } - void add_mutualInductance( - const double& m, const AnalysisType& at, const double& h, const int64_t& ci); - const mutualinductors get_mutualInductance() const { - return mutualInductances_; - } + void set_mutualInductance(const std::pair& mut) { + mutualInductances_.emplace_back(mut); + } + void add_mutualInductance(const double& m, const AnalysisType& at, + const double& h, const int64_t& ci); + const mutualinductors get_mutualInductance() const { + return mutualInductances_; + } - void update_timestep(const double& factor) override; + void update_timestep(const double& factor) override; - void step_back() override { - In2_ = In4_; - } - }; // class Inductor + void step_back() override { In2_ = In4_; } +}; // class Inductor -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Input.hpp b/include/JoSIM/Input.hpp index a1d01c5f..530cde5b 100644 --- a/include/JoSIM/Input.hpp +++ b/include/JoSIM/Input.hpp @@ -3,60 +3,55 @@ #ifndef JOSIM_J_INPUT_H #define JOSIM_J_INPUT_H -#include "JoSIM/TypeDefines.hpp" +#include +#include +#include + #include "JoSIM/AnalysisType.hpp" -#include "JoSIM/FileOutputType.hpp" -#include "JoSIM/ParameterName.hpp" +#include "JoSIM/CliOptions.hpp" #include "JoSIM/Errors.hpp" -#include "JoSIM/Netlist.hpp" +#include "JoSIM/FileOutputType.hpp" +#include "JoSIM/LineInput.hpp" #include "JoSIM/Misc.hpp" +#include "JoSIM/Netlist.hpp" +#include "JoSIM/ParameterName.hpp" #include "JoSIM/Transient.hpp" -#include "JoSIM/LineInput.hpp" -#include "JoSIM/CliOptions.hpp" - -#include -#include -#include +#include "JoSIM/TypeDefines.hpp" namespace JoSIM { - class Input { - public: - Netlist netlist; - Transient transSim; - std::optional globalTemp; - double neB = 1E12; - std::vector fileLines, controls; - std::vector relevantX; - std::unordered_map parameters; - std::optional cli_output_file; - std::vector output_files; - std::optional fileParentPath; - AnalysisType argAnal; - int64_t argVerb; - bool argMin; - bool SLU; - - Input(AnalysisType at = AnalysisType::Phase, - int64_t verb = 0, bool min = false, bool slu = false) : - argAnal(at), - argVerb(verb), - argMin(min), - SLU(slu) {}; - Input(CliOptions& cli_options) { - argAnal = cli_options.analysis_type; - argVerb = cli_options.verbose; - argMin = cli_options.minimal; - cli_output_file = cli_options.output_file; - SLU = cli_options.SLU; - } - - - std::vector read_input( - LineInput& input, string_o fileName = std::nullopt); - void parse_input(string_o fileName = std::nullopt); - void syntax_check_controls(std::vector& controls); - - }; -} // namespace JoSIM +class Input { + public: + Netlist netlist; + Transient transSim; + std::optional globalTemp; + double neB = 1E12; + std::vector fileLines, controls; + std::vector relevantX; + std::unordered_map parameters; + std::optional cli_output_file; + std::vector output_files; + std::optional fileParentPath; + AnalysisType argAnal; + int64_t argVerb; + bool argMin; + bool SLU; + + Input(AnalysisType at = AnalysisType::Phase, int64_t verb = 0, + bool min = false, bool slu = false) + : argAnal(at), argVerb(verb), argMin(min), SLU(slu){}; + Input(CliOptions& cli_options) { + argAnal = cli_options.analysis_type; + argVerb = cli_options.verbose; + argMin = cli_options.minimal; + cli_output_file = cli_options.output_file; + SLU = cli_options.SLU; + } + + std::vector read_input(LineInput& input, + string_o fileName = std::nullopt); + void parse_input(string_o fileName = std::nullopt); + void syntax_check_controls(std::vector& controls); +}; +} // namespace JoSIM #endif diff --git a/include/JoSIM/JJ.hpp b/include/JoSIM/JJ.hpp index b0aa0457..17a6c3ce 100644 --- a/include/JoSIM/JJ.hpp +++ b/include/JoSIM/JJ.hpp @@ -3,93 +3,93 @@ #ifndef JOSIM_JJ_HPP #define JOSIM_JJ_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Function.hpp" +#include "JoSIM/Input.hpp" +#include "JoSIM/Model.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/Model.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/Input.hpp" #include "JoSIM/Spread.hpp" -#include "JoSIM/Function.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Blabel V⁺ V⁻ jjmodel area=value - - V - (hbar/2e)(3/2h)φ = (hbar/2e)(-(2/h)φn-1 + (1/2h)φn-2) - V - (2Rh/(3RC + 2h))Io = - -(2Rh/(3RC + 2h))(Icsinφ0 - (2C/h)Vn-1 + (C/2h)Vn-2) - φ0 = (4/3)φn-1 - (1/3)φn-2 + (2e/hbar)(2h/3)v0 - v0 = (5/2)Vn-1 - 2Vn-2 + (1/2)Vn-3 - - ⎡ 0 0 0 1⎤ ⎡ V⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 -1⎟ ⎜ V⁻⎟ = ⎜ 0⎟ - ⎜ 1 -1 -(hbar/2e)(3/2h) 0⎟ ⎜ φ ⎟ ⎜ RHS1⎟ - ⎣ 1 -1 0 -(2Rh/(3RC + 2h))⎦ ⎣ Io⎦ ⎣ RHS2⎦ - - RHS1 = (hbar/2e)(-(2/h)φn-1 + (1/2h)φn-2) - RHS2 = -(2Rh/(3RC + 2h))(Icsinφ0 - (2C/h)Vn-1 + (C/2h)Vn-2) - - (PHASE) - φ - (2e/hbar)(2h/3)V = (4/3)φn-1 - (1/3)φn-2 - - ⎡ 0 0 0 1⎤ ⎡ φ⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 -1⎟ ⎜ φ⁻⎟ = ⎜ 0⎟ - ⎜ 1 -1 -(2e/hbar)(2h/3) 0⎟ ⎜ V ⎟ ⎜ RHS1⎟ - ⎣ 1 -1 0 -(2Rh/(3RC + 2h))⎦ ⎣ Io⎦ ⎣ RHS2⎦ - - RHS1 = (4/3)φn-1 - (1/3)φn-2 - */ - - class JJ : public BasicComponent { - private: - int64_t hDepPos_ = 0; - int64_t state_ = 0; - double h_ = 0.0; - public: - int64_t variableIndex_ = 0; - double area_ = 1.0; - std::optional Ic_, temp_, neb_, spAmp_; - Model model_; - double phaseConst_ = 0.0; - double lowerB_ = 0.0, upperB_ = 0.0, gLarge_ = 0.0; - double del0_ = 0.0, del_ = 0.0; - double pn1_ = 0.0, pn2_ = pn1_, pn3_ = pn2_, pn4_ = pn3_, phi0_ = 0.0; - double vn1_ = 0.0, vn2_ = vn1_, vn3_ = vn2_, vn4_ = vn3_, vn5_ = vn4_, - vn6_ = vn5_; - double it_ = 0.0; - JoSIM::AnalysisType at_; - std::optional thermalNoise; - - JJ( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi); - - double subgap_impedance(); - double transient_impedance(); - double normal_impedance(); - - void set_matrix_info(); - - void set_model( - const tokens_t& t, const vector_pair_t& models, - const string_o& subc); - - bool update_value(const double& v); - - void step_back() override { - pn2_ = pn4_; - vn3_ = vn6_; - vn2_ = vn5_; - } - }; // class JJ - -} // namespace JoSIM +/* + Blabel V⁺ V⁻ jjmodel area=value + + V - (hbar/2e)(3/2h)φ = (hbar/2e)(-(2/h)φn-1 + (1/2h)φn-2) + V - (2Rh/(3RC + 2h))Io = + -(2Rh/(3RC + 2h))(Icsinφ0 - (2C/h)Vn-1 + (C/2h)Vn-2) + φ0 = (4/3)φn-1 - (1/3)φn-2 + (2e/hbar)(2h/3)v0 + v0 = (5/2)Vn-1 - 2Vn-2 + (1/2)Vn-3 + + ⎡ 0 0 0 1⎤ ⎡ V⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 -1⎟ ⎜ V⁻⎟ = ⎜ 0⎟ + ⎜ 1 -1 -(hbar/2e)(3/2h) 0⎟ ⎜ φ ⎟ ⎜ RHS1⎟ + ⎣ 1 -1 0 -(2Rh/(3RC + 2h))⎦ ⎣ Io⎦ ⎣ RHS2⎦ + + RHS1 = (hbar/2e)(-(2/h)φn-1 + (1/2h)φn-2) + RHS2 = -(2Rh/(3RC + 2h))(Icsinφ0 - (2C/h)Vn-1 + (C/2h)Vn-2) + + (PHASE) + φ - (2e/hbar)(2h/3)V = (4/3)φn-1 - (1/3)φn-2 + + ⎡ 0 0 0 1⎤ ⎡ φ⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 -1⎟ ⎜ φ⁻⎟ = ⎜ 0⎟ + ⎜ 1 -1 -(2e/hbar)(2h/3) 0⎟ ⎜ V ⎟ ⎜ RHS1⎟ + ⎣ 1 -1 0 -(2Rh/(3RC + 2h))⎦ ⎣ Io⎦ ⎣ RHS2⎦ + + RHS1 = (4/3)φn-1 - (1/3)φn-2 +*/ + +class JJ : public BasicComponent { + private: + int64_t hDepPos_ = 0; + int64_t state_ = 0; + double h_ = 0.0; + + public: + int64_t variableIndex_ = 0; + double area_ = 1.0; + std::optional Ic_, temp_, neb_, spAmp_; + Model model_; + double phaseConst_ = 0.0; + double lowerB_ = 0.0, upperB_ = 0.0, gLarge_ = 0.0; + double del0_ = 0.0, del_ = 0.0; + double pn1_ = 0.0, pn2_ = pn1_, pn3_ = pn2_, pn4_ = pn3_, phi0_ = 0.0; + double vn1_ = 0.0, vn2_ = vn1_, vn3_ = vn2_, vn4_ = vn3_, vn5_ = vn4_, + vn6_ = vn5_; + double it_ = 0.0; + JoSIM::AnalysisType at_; + std::optional thermalNoise; + + JJ(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi); + + double subgap_impedance(); + double transient_impedance(); + double normal_impedance(); + + void set_matrix_info(); + + void set_model(const tokens_t& t, + const vector_pair_t& models, + const string_o& subc); + + bool update_value(const double& v); + + void step_back() override { + pn2_ = pn4_; + vn3_ = vn6_; + vn2_ = vn5_; + } +}; // class JJ + +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/LUSolve.hpp b/include/JoSIM/LUSolve.hpp index 8008f0bd..868e538b 100644 --- a/include/JoSIM/LUSolve.hpp +++ b/include/JoSIM/LUSolve.hpp @@ -9,38 +9,38 @@ namespace JoSIM { - class LUSolve { - private: - char equed[1] = { 'N' }; - trans_t trans; - SuperMatrix A, L, U, B, X; - GlobalLU_t Glu; - - long long* perm_r,* perm_c; - long long* etree; - void* work = nullptr; - long long info, lwork, nrhs, ldx; - long long m, n, nnz; - double* rhsb,* rhsx,* xact; - double* R,* C; - double* ferr,* berr; - double rpg, rcond; - mem_usage_t mem_usage; - superlu_options_t options; - SuperLUStat_t stat; - bool allocated = false; - bool constructed = false; - - public: - LUSolve(); - void create_matrix(int64_t shape, std::vector& nz, - std::vector& ci, std::vector& rp); - void factorize(bool symbolic = false); - bool is_stable(); - void solve(std::vector& x); - void free(); - }; - -} +class LUSolve { + private: + char equed[1] = {'N'}; + trans_t trans; + SuperMatrix A, L, U, B, X; + GlobalLU_t Glu; + + long long *perm_r, *perm_c; + long long* etree; + void* work = nullptr; + long long info, lwork, nrhs, ldx; + long long m, n, nnz; + double *rhsb, *rhsx, *xact; + double *R, *C; + double *ferr, *berr; + double rpg, rcond; + mem_usage_t mem_usage; + superlu_options_t options; + SuperLUStat_t stat; + bool allocated = false; + bool constructed = false; + + public: + LUSolve(); + void create_matrix(int64_t shape, std::vector& nz, + std::vector& ci, std::vector& rp); + void factorize(bool symbolic = false); + bool is_stable(); + void solve(std::vector& x); + void free(); +}; + +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/LineInput.hpp b/include/JoSIM/LineInput.hpp index 5d57dfe5..4a21a268 100644 --- a/include/JoSIM/LineInput.hpp +++ b/include/JoSIM/LineInput.hpp @@ -3,56 +3,49 @@ #ifndef JOSIM_LINEINPUT_HPP #define JOSIM_LINEINPUT_HPP -#include "JoSIM/Errors.hpp" - +#include +#include #include #include -#include -#include + +#include "JoSIM/Errors.hpp" namespace JoSIM { - class LineInput { - public: - virtual std::string_view line() = 0; - virtual bool next() = 0; - }; - - class ConsoleInput : public LineInput { - std::string buffer_; - public: - std::string_view line() override { - return buffer_; - } - bool next() override { - return bool(std::getline(std::cin, buffer_)); - } - ConsoleInput() {}; - }; - - class FileInput : public LineInput { - std::string buffer_; - std::ifstream file_; - private: - bool open(const std::string& file) { - file_.open(file, std::ios::in | std::ios::binary); - if (!file_.is_open()) { - Errors::input_errors(InputErrors::CANNOT_OPEN_FILE, file); - } - return true; - } - public: - std::string_view line() override { - return buffer_; +class LineInput { + public: + virtual std::string_view line() = 0; + virtual bool next() = 0; +}; + +class ConsoleInput : public LineInput { + std::string buffer_; + + public: + std::string_view line() override { return buffer_; } + bool next() override { return bool(std::getline(std::cin, buffer_)); } + ConsoleInput(){}; +}; + +class FileInput : public LineInput { + std::string buffer_; + std::ifstream file_; + + private: + bool open(const std::string& file) { + file_.open(file, std::ios::in | std::ios::binary); + if (!file_.is_open()) { + Errors::input_errors(InputErrors::CANNOT_OPEN_FILE, file); } - bool next() override { - return bool(std::getline(file_, buffer_)); - } - FileInput(const std::string& file) { - open(file); - } - }; + return true; + } + + public: + std::string_view line() override { return buffer_; } + bool next() override { return bool(std::getline(file_, buffer_)); } + FileInput(const std::string& file) { open(file); } +}; -} // namespace JoSIM +} // namespace JoSIM -#endif // JOSIM_LINEINPUT_HPP +#endif // JOSIM_LINEINPUT_HPP diff --git a/include/JoSIM/Matrix.hpp b/include/JoSIM/Matrix.hpp index bd13ca64..cd965c59 100644 --- a/include/JoSIM/Matrix.hpp +++ b/include/JoSIM/Matrix.hpp @@ -3,47 +3,48 @@ #ifndef JOSIM_MATRIX_HPP #define JOSIM_MATRIX_HPP +#include +#include + #include "JoSIM/AnalysisType.hpp" #include "JoSIM/Components.hpp" -#include "JoSIM/Input.hpp" #include "JoSIM/Errors.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/RelevantTrace.hpp" #include "JoSIM/Spread.hpp" -#include -#include - namespace JoSIM { - class Matrix { - private: - std::vector nodeConfig, nodeConfig2; - bool needsTR_ = true; - public: - AnalysisType analysisType = AnalysisType::Phase; - std::vector sourcegen; +class Matrix { + private: + std::vector nodeConfig, nodeConfig2; + bool needsTR_ = true; + + public: + AnalysisType analysisType = AnalysisType::Phase; + std::vector sourcegen; - Components components; - Spread spread; - std::unordered_map nm; - nodeconnections nc; - std::unordered_set lm; - int64_t branchIndex = 0; - std::vector nz; - std::vector ci, rp; - std::vector relevantTraces; - std::vector relevantIndices; + Components components; + Spread spread; + std::unordered_map nm; + nodeconnections nc; + std::unordered_set lm; + int64_t branchIndex = 0; + std::vector nz; + std::vector ci, rp; + std::vector relevantTraces; + std::vector relevantIndices; - Matrix() {}; - void create_matrix(Input& iObj); - void setup(Input& iObj); - void create_components(Input& iObj); - void handle_mutual_inductance(Input& iObj); - void reduce_step(Input& iObj); - void create_csr(); - void create_nz(); - void create_ci(); - void create_rp(); - }; -} // namespace JoSIM + Matrix(){}; + void create_matrix(Input& iObj); + void setup(Input& iObj); + void create_components(Input& iObj); + void handle_mutual_inductance(Input& iObj); + void reduce_step(Input& iObj); + void create_csr(); + void create_nz(); + void create_ci(); + void create_rp(); +}; +} // namespace JoSIM #endif diff --git a/include/JoSIM/Misc.hpp b/include/JoSIM/Misc.hpp index 82063cf4..3ddc1d86 100644 --- a/include/JoSIM/Misc.hpp +++ b/include/JoSIM/Misc.hpp @@ -3,90 +3,83 @@ #ifndef JOSIM_MISC_HPP #define JOSIM_MISC_HPP -#include "JoSIM/TypeDefines.hpp" -#include "JoSIM/Parameters.hpp" -#include "JoSIM/Input.hpp" - -#include -#include -#include -#include #include +#include +#include #include +#include +#include -namespace JoSIM { - class Input; - namespace Misc { - double string_constant(const std::string& s); +#include "JoSIM/Input.hpp" +#include "JoSIM/Parameters.hpp" +#include "JoSIM/TypeDefines.hpp" - bool isclose(const double &a, const double& b); +namespace JoSIM { +class Input; +namespace Misc { +double string_constant(const std::string& s); - std::string file_from_path(const std::string& path); +bool isclose(const double& a, const double& b); - bool has_suffix(const std::string& str, - const std::string& suffix); +std::string file_from_path(const std::string& path); - bool starts_with(const std::string& input, - char test); +bool has_suffix(const std::string& str, const std::string& suffix); - // View vector of strings as a string with a default delimiter - std::string vector_to_string(const tokens_t& s, std::string d = " "); +bool starts_with(const std::string& input, char test); +// View vector of strings as a string with a default delimiter +std::string vector_to_string(const tokens_t& s, std::string d = " "); - // Split a string into tokens with a default delimiter - tokens_t tokenize(const std::string& c, - std::string d = " \t", - bool trimEmpty = true, - bool trimSpaces = false, - int64_t count = 0); +// Split a string into tokens with a default delimiter +tokens_t tokenize(const std::string& c, std::string d = " \t", + bool trimEmpty = true, bool trimSpaces = false, + int64_t count = 0); - void ltrim(std::string& s); +void ltrim(std::string& s); - void rtrim(std::string& s); +void rtrim(std::string& s); - double modifier(const std::string& value); +double modifier(const std::string& value); - void unique_push(std::vector& vector, - const std::string& string); +void unique_push(std::vector& vector, const std::string& string); - int64_t index_of(const std::vector& vector, - const std::string& value); +int64_t index_of(const std::vector& vector, + const std::string& value); - std::string substring_after(const std::string& str, - const std::string& whatpart); +std::string substring_after(const std::string& str, + const std::string& whatpart); - std::string substring_before(const std::string& str, - const std::string& whatpart); +std::string substring_before(const std::string& str, + const std::string& whatpart); - bool findX(const std::vector& segment, - std::string& theLine, - int64_t& linePos); +bool findX(const std::vector& segment, std::string& theLine, + int64_t& linePos); - template - std::pair flip_pair(const std::pair& p) { - return std::pair(p.second, p.first); - } +template +std::pair flip_pair(const std::pair& p) { + return std::pair(p.second, p.first); +} - template - std::map flip_map(const std::unordered_map& src) { - std::map dst; - std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), - flip_pair); - return dst; - } +template +std::map flip_map(const std::unordered_map& src) { + std::map dst; + std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), + flip_pair); + return dst; +} - template - std::string precise_to_string(const T a_value) { - std::ostringstream out; - out << std::uppercase << - std::setprecision(std::numeric_limits::digits10 + 1) << - a_value; - return out.str(); - } +template +std::string precise_to_string(const T a_value) { + std::ostringstream out; + out << std::uppercase + << std::setprecision(std::numeric_limits::digits10 + 1) + << a_value; + return out.str(); +} - int64_t numDigits(int64_t number); +int64_t numDigits(int64_t number); - double grand(); - } // namespace Misc -} // namespace JoSIM +double grand(); +} // namespace Misc +} // namespace JoSIM #endif diff --git a/include/JoSIM/Model.hpp b/include/JoSIM/Model.hpp index db2262d1..e529c70b 100644 --- a/include/JoSIM/Model.hpp +++ b/include/JoSIM/Model.hpp @@ -8,127 +8,75 @@ #include "JoSIM/TypeDefines.hpp" namespace JoSIM { - class Model { - private: - std::string modelName_; - double vg_; - double ic_; - int64_t rtype_; - double rn_; - double r0_; - double c_; - double t_; - double tc_; - double deltaV_; - double d_; - double icFct_; - double phiOff_; - bool tDep_; +class Model { + private: + std::string modelName_; + double vg_; + double ic_; + double cpr_; + int64_t rtype_; + double rn_; + double r0_; + double c_; + double t_; + double tc_; + double deltaV_; + double d_; + double icFct_; + double phiOff_; + bool tDep_; - public: - Model() : - vg_(2.8E-3), - ic_(1E-3), - rtype_(1), - rn_(5), - r0_(30), - c_(2.5E-12), - t_(4.2), - tc_(9.1), - deltaV_(0.1E-3), - d_(0), - icFct_(Constants::PI / 4), - phiOff_(0), - tDep_(false) {}; + public: + Model() + : vg_(2.8E-3), + ic_(1E-3), + cpr_(1.0), + rtype_(1), + rn_(5), + r0_(30), + c_(2.5E-12), + t_(4.2), + tc_(9.1), + deltaV_(0.1E-3), + d_(0), + icFct_(Constants::PI / 4), + phiOff_(0), + tDep_(false){}; - std::string modelName() const { - return modelName_; - } - void modelName(const std::string& n) { - modelName_ = n; - } - double vg() const { - return vg_; - } - void vg(const double& v) { - vg_ = v; - } - double ic() const { - return ic_; - } - void ic(const double& i) { - ic_ = i; - } - int64_t rtype() const { - return rtype_; - } - void rtype(const int64_t& r) { - rtype_ = r; - } - double rn() const { - return rn_; - } - void rn(const double& r) { - rn_ = r; - } - double r0() const { - return r0_; - } - void r0(const double& r) { - r0_ = r; - } - double c() const { - return c_; - } - void c(const double& c) { - c_ = c; - } - double t() const { - return t_; - } - void t(const double& t) { - t_ = t; - } - double tc() const { - return tc_; - } - void tc(const double& t) { - tc_ = t; - } - double deltaV() const { - return deltaV_; - } - void deltaV(const double& d) { - deltaV_ = d; - } - double d() const { - return d_; - } - void d(const double& t) { - d_ = t; - } - double icFct() const { - return icFct_; - } - void icFct(const double& r) { - icFct_ = r; - } - double phiOff() const { - return phiOff_; - } - void phiOff(const double& o) { - phiOff_ = o; - } - bool tDep() { - return tDep_; - } - void tDep(bool b) { - tDep_ = b; - } - static void parse_model( - const std::pair& s, - vector_pair_t& models, const param_map& p); - }; -} // namespace JoSIM + std::string modelName() const { return modelName_; } + void modelName(const std::string& n) { modelName_ = n; } + double vg() const { return vg_; } + void vg(const double& v) { vg_ = v; } + double ic() const { return ic_; } + void ic(const double& i) { ic_ = i; } + double cpr() const { return cpr_; } + void cpr(const double& i) { cpr_ = i; } + int64_t rtype() const { return rtype_; } + void rtype(const int64_t& r) { rtype_ = r; } + double rn() const { return rn_; } + void rn(const double& r) { rn_ = r; } + double r0() const { return r0_; } + void r0(const double& r) { r0_ = r; } + double c() const { return c_; } + void c(const double& c) { c_ = c; } + double t() const { return t_; } + void t(const double& t) { t_ = t; } + double tc() const { return tc_; } + void tc(const double& t) { tc_ = t; } + double deltaV() const { return deltaV_; } + void deltaV(const double& d) { deltaV_ = d; } + double d() const { return d_; } + void d(const double& t) { d_ = t; } + double icFct() const { return icFct_; } + void icFct(const double& r) { icFct_ = r; } + double phiOff() const { return phiOff_; } + void phiOff(const double& o) { phiOff_ = o; } + bool tDep() { return tDep_; } + void tDep(bool b) { tDep_ = b; } + static void parse_model(const std::pair& s, + vector_pair_t& models, + const param_map& p); +}; +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Netlist.hpp b/include/JoSIM/Netlist.hpp index 933ae465..aff49b3b 100644 --- a/include/JoSIM/Netlist.hpp +++ b/include/JoSIM/Netlist.hpp @@ -3,75 +3,76 @@ #ifndef JOSIM_NETLIST_HPP #define JOSIM_NETLIST_HPP -#include "JoSIM/TypeDefines.hpp" -#include "JoSIM/Parameters.hpp" -#include "JoSIM/Model.hpp" - #include -#include #include +#include + +#include "JoSIM/Model.hpp" +#include "JoSIM/Parameters.hpp" +#include "JoSIM/TypeDefines.hpp" typedef std::unordered_map s_map; namespace JoSIM { - struct pair_hash { - template - std::size_t operator()(const std::pair& p) const noexcept { - std::size_t h1 = std::hash{}(p.first); - std::size_t h2 = std::hash{}(p.second); - return h1 ^ (h2 << 1); - } - }; +struct pair_hash { + template + std::size_t operator()(const std::pair& p) const noexcept { + std::size_t h1 = std::hash{}(p.first); + std::size_t h2 = std::hash{}(p.second); + return h1 ^ (h2 << 1); + } +}; - class Subcircuit { - public: - tokens_t io; - std::vector> lines; - tokens_t subckts; - int64_t jjCount, compCount, subcktCounter; - bool containsSubckt; - Subcircuit() : - jjCount(0), - compCount(0), - subcktCounter(0), - containsSubckt(false) { +class Subcircuit { + public: + tokens_t io; + std::vector> lines; + tokens_t subckts; + int64_t jjCount, compCount, subcktCounter; + bool containsSubckt; + Subcircuit() + : jjCount(0), + compCount(0), + subcktCounter(0), + containsSubckt(false){ - }; - }; + }; +}; - class Input; +class Input; - class Netlist { - private: - void id_io_subc_label( +class Netlist { + private: + void id_io_subc_label( const tokens_t& lineTokens, tokens_t& io, s_map& params, std::string& subcktName, std::string& label, const std::unordered_map& subcircuits); - bool rename_io_nodes( - std::string& node, const tokens_t& subIO, const tokens_t& parentIO); - void expand_io(Subcircuit& subc, s_map& params, const tokens_t& io, - const std::string& label); - void insert_parameter(tokens_t& t, s_map& params); - public: - std::unordered_map< - std::pair, tokens_t, pair_hash> models; - std::vector> models_new; - std::unordered_map subcircuits; - std::unordered_map subcktLookup; - std::vector maindesign; - tokens_t subckts; - std::vector> expNetlist; - int64_t jjCount, compCount, subcktCounter, nestedSubcktCount, subcktTotal = 0; - bool containsSubckt, argMin = false; - Netlist() : - jjCount(0), - compCount(0), - subcktCounter(0), - nestedSubcktCount(0), - containsSubckt(false) {}; - void expand_subcircuits(); - void expand_maindesign(); - }; + bool rename_io_nodes(std::string& node, const tokens_t& subIO, + const tokens_t& parentIO); + void expand_io(Subcircuit& subc, s_map& params, const tokens_t& io, + const std::string& label); + void insert_parameter(tokens_t& t, s_map& params); + + public: + std::unordered_map, tokens_t, pair_hash> + models; + std::vector> models_new; + std::unordered_map subcircuits; + std::unordered_map subcktLookup; + std::vector maindesign; + tokens_t subckts; + std::vector> expNetlist; + int64_t jjCount, compCount, subcktCounter, nestedSubcktCount, subcktTotal = 0; + bool containsSubckt, argMin = false; + Netlist() + : jjCount(0), + compCount(0), + subcktCounter(0), + nestedSubcktCount(0), + containsSubckt(false){}; + void expand_subcircuits(); + void expand_maindesign(); +}; -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Noise.hpp b/include/JoSIM/Noise.hpp index f626cef8..83ea7317 100644 --- a/include/JoSIM/Noise.hpp +++ b/include/JoSIM/Noise.hpp @@ -7,14 +7,12 @@ namespace JoSIM { - class Noise { - public: - static void determine_global_temperature(Input& iObj); - static void determine_noise_effective_bandwidth(Input& iObj); - static double determine_spectral_amplitude(const double& R, - const double& T); - - }; -} +class Noise { + public: + static void determine_global_temperature(Input& iObj); + static void determine_noise_effective_bandwidth(Input& iObj); + static double determine_spectral_amplitude(const double& R, const double& T); +}; +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Output.hpp b/include/JoSIM/Output.hpp index 68ac87e9..60e357a2 100644 --- a/include/JoSIM/Output.hpp +++ b/include/JoSIM/Output.hpp @@ -3,42 +3,38 @@ #ifndef JOSIM_OUTPUT_HPP #define JOSIM_OUTPUT_HPP +#include "JoSIM/Input.hpp" #include "JoSIM/Matrix.hpp" #include "JoSIM/Misc.hpp" #include "JoSIM/Simulation.hpp" -#include "JoSIM/Input.hpp" namespace JoSIM { - class Trace { - public: - std::string name_; - char type_; - int64_t fileIndex = -1; - std::vector data_; - Trace(const std::string& name) { - name_ = name; - } - ~Trace() {}; - }; +class Trace { + public: + std::string name_; + char type_; + int64_t fileIndex = -1; + std::vector data_; + Trace(const std::string& name) { name_ = name; } + ~Trace(){}; +}; - class Output { - public: - std::vector traces; - std::vector timesteps; - Output() {}; - Output(Input& iObj, Matrix& mObj, Simulation& sObj); - void write_output(const Input& iObj, Matrix& mObj, Simulation& sObj); +class Output { + public: + std::vector traces; + std::vector timesteps; + Output(){}; + Output(Input& iObj, Matrix& mObj, Simulation& sObj); + void write_output(const Input& iObj, Matrix& mObj, Simulation& sObj); - void format_csv_or_dat(const std::string& filename, - const char& delimiter, - bool argmin = true, - int64_t fIndex = -1); + void format_csv_or_dat(const std::string& filename, const char& delimiter, + bool argmin = true, int64_t fIndex = -1); - void format_raw(const std::string& filename, bool argmin = true, - int64_t fIndex = -1); + void format_raw(const std::string& filename, bool argmin = true, + int64_t fIndex = -1); - void format_cout(const bool& argMin); - }; -} // namespace JoSIM + void format_cout(const bool& argMin); +}; +} // namespace JoSIM #endif diff --git a/include/JoSIM/ParameterName.hpp b/include/JoSIM/ParameterName.hpp index 4ebac751..c43af68c 100644 --- a/include/JoSIM/ParameterName.hpp +++ b/include/JoSIM/ParameterName.hpp @@ -3,56 +3,55 @@ #ifndef JOSIM_PARAMETERNAME_HPP #define JOSIM_PARAMETERNAME_HPP +#include #include #include -#include namespace JoSIM { - class ParameterName { - std::string name_; - std::optional subcircuit_; +class ParameterName { + std::string name_; + std::optional subcircuit_; - public: - ParameterName(std::string name, std::optional subcircuit) + public: + ParameterName(std::string name, std::optional subcircuit) : name_(std::move(name)), subcircuit_(std::move(subcircuit)) { - // Empty - } + // Empty + } - /// Get parameter name - const std::string& name() const noexcept { - return name_; - } + /// Get parameter name + const std::string& name() const noexcept { return name_; } - /// Get subcircuit name of parameter, nullopt if it is in global scope - const std::optional& subcircuit() const noexcept { - return subcircuit_; - } + /// Get subcircuit name of parameter, nullopt if it is in global scope + const std::optional& subcircuit() const noexcept { + return subcircuit_; + } - /// Equality comparison - bool operator==(const ParameterName& other) const noexcept { - return (name_ == other.name_ && subcircuit_ == other.subcircuit_); - } - }; + /// Equality comparison + bool operator==(const ParameterName& other) const noexcept { + return (name_ == other.name_ && subcircuit_ == other.subcircuit_); + } +}; -} // namespace JoSIM +} // namespace JoSIM namespace std { - // Hash function for ParameterName - template <> struct hash { - std::size_t operator()(const JoSIM::ParameterName& parameter_name) const { - using std::hash; - using std::string; +// Hash function for ParameterName +template <> +struct hash { + std::size_t operator()(const JoSIM::ParameterName& parameter_name) const { + using std::hash; + using std::string; - auto hash_name = hash()(parameter_name.name()); - auto hash_subcircuit = + auto hash_name = hash()(parameter_name.name()); + auto hash_subcircuit = hash>()(parameter_name.subcircuit()); - return hash_name ^ (hash_subcircuit << 1); - } - }; + return hash_name ^ (hash_subcircuit << 1); + } +}; -} // namespace std +} // namespace std -#endif // JOSIM_PARAMETERNAME_HPP +#endif // JOSIM_PARAMETERNAME_HPP diff --git a/include/JoSIM/Parameters.hpp b/include/JoSIM/Parameters.hpp index 0d84b434..7bfe3892 100644 --- a/include/JoSIM/Parameters.hpp +++ b/include/JoSIM/Parameters.hpp @@ -3,69 +3,57 @@ #ifndef JOSIM_PARAMETERS_HPP #define JOSIM_PARAMETERS_HPP -#include "JoSIM/ParameterName.hpp" -#include "JoSIM/TypeDefines.hpp" - +#include +#include #include -#include #include -#include -#include +#include + +#include "JoSIM/ParameterName.hpp" +#include "JoSIM/TypeDefines.hpp" namespace JoSIM { - class Parameter { - private: - std::string expression_; - double_o value_; +class Parameter { + private: + std::string expression_; + double_o value_; - public: - Parameter() {}; + public: + Parameter(){}; - void set_expression(const std::string& s) { - expression_ = s; - }; - void reset_value() { - value_ = std::nullopt; - } - void set_value(const double& v) { - value_ = v; - }; + void set_expression(const std::string& s) { expression_ = s; }; + void reset_value() { value_ = std::nullopt; } + void set_value(const double& v) { value_ = v; }; - std::string get_expression() const { - return expression_; - }; - double_o get_value() const { - return value_; - }; - }; + std::string get_expression() const { return expression_; }; + double_o get_value() const { return value_; }; +}; - // Shorthand for long type - using param_map = std::unordered_map; +// Shorthand for long type +using param_map = std::unordered_map; - void expand_inline_parameters( - std::vector& s, param_map& parameters); +void expand_inline_parameters(std::vector& s, + param_map& parameters); - void create_parameter( - const tokens_t& s, param_map& parameters, string_o subc = std::nullopt); +void create_parameter(const tokens_t& s, param_map& parameters, + string_o subc = std::nullopt); - double parse_param( - const std::string& expr, const param_map& params, - string_o subc = std::nullopt, - bool single = true); +double parse_param(const std::string& expr, const param_map& params, + string_o subc = std::nullopt, bool single = true); - int64_t precedence_lvl(const std::string& op); +int64_t precedence_lvl(const std::string& op); - double parse_operator( - const std::string& op, double val1, double val2, int64_t& popCount); +double parse_operator(const std::string& op, double val1, double val2, + int64_t& popCount); - void parse_parameters(param_map& parameters); +void parse_parameters(param_map& parameters); - void update_parameters(param_map& parameters); +void update_parameters(param_map& parameters); - void expand_inline_parameters( - std::pair& s, param_map& parameters); +void expand_inline_parameters(std::pair& s, + param_map& parameters); -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/PhaseSource.hpp b/include/JoSIM/PhaseSource.hpp index d4497237..ada7b6f1 100644 --- a/include/JoSIM/PhaseSource.hpp +++ b/include/JoSIM/PhaseSource.hpp @@ -3,34 +3,32 @@ #ifndef JOSIM_PHASESOURCE_HPP #define JOSIM_PHASESOURCE_HPP -#include "JoSIM/BasicComponent.hpp" -#include "JoSIM/ParameterName.hpp" -#include "JoSIM/Parameters.hpp" - -#include +#include #include #include -#include +#include +#include "JoSIM/BasicComponent.hpp" +#include "JoSIM/ParameterName.hpp" +#include "JoSIM/Parameters.hpp" namespace JoSIM { - /* - Plabel φ⁺ φ⁻ sourcetype +/* + Plabel φ⁺ φ⁻ sourcetype - ⎡ 0 0 1⎤ ⎡φ⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜φ⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 0⎦ ⎣Io⎦ ⎣ 0⎦ - */ + ⎡ 0 0 1⎤ ⎡φ⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜φ⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 0⎦ ⎣Io⎦ ⎣ 0⎦ +*/ - class PhaseSource : public BasicComponent { - public: - int64_t sourceIndex_; - PhaseSource( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, int64_t& bi, const int64_t& ci); - }; // class PhaseSource +class PhaseSource : public BasicComponent { + public: + int64_t sourceIndex_; + PhaseSource(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, int64_t& bi, const int64_t& ci); +}; // class PhaseSource -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/ProgressBar.hpp b/include/JoSIM/ProgressBar.hpp index 88c68ea1..d6f5f144 100644 --- a/include/JoSIM/ProgressBar.hpp +++ b/include/JoSIM/ProgressBar.hpp @@ -4,100 +4,84 @@ #define JOSIM_PROGRESSBAR_HPP #include +#include #include #include -#include namespace JoSIM { - class ProgressBar { - private: - std::atomic complete_ = false; - std::atomic c_progress_{ 0.0f }; - std::atomic progress_{ 0.0f }; - std::atomic total_{ 1.0f }; - std::atomic bar_width_{ 60 }; - std::string fill_{ "#" }, remainder_{ " " }, status_text_{ "" }; - std::vector threads_; - - public: - void set_progress(float value) { - progress_ = value; - } +class ProgressBar { + private: + std::atomic complete_ = false; + std::atomic c_progress_{0.0f}; + std::atomic progress_{0.0f}; + std::atomic total_{1.0f}; + std::atomic bar_width_{60}; + std::string fill_{"#"}, remainder_{" "}, status_text_{""}; + std::vector threads_; - void set_total(float value) { - total_ = value; - } + public: + void set_progress(float value) { progress_ = value; } - void set_currentprogress(float value) { - c_progress_ = value; - } + void set_total(float value) { total_ = value; } - void set_bar_width(size_t width) { - bar_width_ = width; - } + void set_currentprogress(float value) { c_progress_ = value; } - void fill_bar_progress_with(const std::string& chars) { - fill_ = chars; - } + void set_bar_width(size_t width) { bar_width_ = width; } - void fill_bar_remainder_with(const std::string& chars) { - remainder_ = chars; - } + void fill_bar_progress_with(const std::string& chars) { fill_ = chars; } - void set_status_text(const std::string& status) { - status_text_ = status; - } + void fill_bar_remainder_with(const std::string& chars) { remainder_ = chars; } - void update(float value, std::ostream& os = std::cout) { - set_progress(value); - } + void set_status_text(const std::string& status) { status_text_ = status; } + + void update(float value, std::ostream& os = std::cout) { + set_progress(value); + } - void write_progress(float perc, std::ostream& os = std::cout) { - os << "\r" << std::flush; - os << "["; - const auto completed = + void write_progress(float perc, std::ostream& os = std::cout) { + os << "\r" << std::flush; + os << "["; + const auto completed = static_cast(perc) * static_cast(bar_width_) / 100.0; - for (size_t i = 0; i < bar_width_; ++i) { - if (i <= completed) - os << fill_; - else - os << remainder_; - } - os << "]"; - os << " " << std::min(static_cast(perc), size_t(100)) << "%"; - os << " " << status_text_; + for (size_t i = 0; i < bar_width_; ++i) { + if (i <= completed) + os << fill_; + else + os << remainder_; } - - void thread_print() { - while (!complete_) { - float perc = progress_ / total_ * 100; - if (perc > c_progress_) { - write_progress(perc); - set_currentprogress(perc); - } + os << "]"; + os << " " << std::min(static_cast(perc), size_t(100)) << "%"; + os << " " << status_text_; + } + + void thread_print() { + while (!complete_) { + float perc = progress_ / total_ * 100; + if (perc > c_progress_) { + write_progress(perc); + set_currentprogress(perc); } - write_progress(100.0f); } + write_progress(100.0f); + } - void create_thread() { - threads_.push_back(std::thread(&ProgressBar::thread_print, this)); - } - - void complete(std::ostream& os = std::cout) { - complete_ = true; - if (!threads_.empty()) threads_.back().join(); - } + void create_thread() { + threads_.push_back(std::thread(&ProgressBar::thread_print, this)); + } - ~ProgressBar() { - complete_ = true; - if (!threads_.empty()) - if (threads_.back().joinable()) - threads_.back().join(); - } + void complete(std::ostream& os = std::cout) { + complete_ = true; + if (!threads_.empty()) threads_.back().join(); + } - }; + ~ProgressBar() { + complete_ = true; + if (!threads_.empty()) + if (threads_.back().joinable()) threads_.back().join(); + } +}; } // namespace JoSIM -#endif // JOSIM_PROGRESSBAR_HPP \ No newline at end of file +#endif // JOSIM_PROGRESSBAR_HPP \ No newline at end of file diff --git a/include/JoSIM/RelevantTrace.hpp b/include/JoSIM/RelevantTrace.hpp index ca1da326..8c16b511 100644 --- a/include/JoSIM/RelevantTrace.hpp +++ b/include/JoSIM/RelevantTrace.hpp @@ -3,73 +3,71 @@ #ifndef JOSIM_RELEVANTTRACES_HPP #define JOSIM_RELEVANTTRACES_HPP -#include "JoSIM/Misc.hpp" #include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" #include "JoSIM/TypeDefines.hpp" - namespace JoSIM { - class Matrix; - class Input; - enum class StorageType : int64_t { - Voltage = 0, Phase = 1, Current = 2 - }; +class Matrix; +class Input; +enum class StorageType : int64_t { Voltage = 0, Phase = 1, Current = 2 }; - struct target_less { - template - bool operator()(It const& a, It const& b) const { - return *a < *b; - } - }; +struct target_less { + template + bool operator()(It const& a, It const& b) const { + return *a < *b; + } +}; - struct target_equal { - template - bool operator()(It const& a, It const& b) const { - return *a == *b; - } - }; +struct target_equal { + template + bool operator()(It const& a, It const& b) const { + return *a == *b; + } +}; - template It uniquify(It begin, It const end) { - std::vector v; - v.reserve(static_cast(std::distance(begin, end))); - for (It i = begin; i != end; ++i) { - v.push_back(i); - } - std::sort(v.begin(), v.end(), target_less()); - v.erase(std::unique(v.begin(), v.end(), target_equal()), v.end()); - std::sort(v.begin(), v.end()); - size_t j = 0; - for (It i = begin; i != end && j != v.size(); ++i) { - if (i == v[j]) { - using std::iter_swap; iter_swap(i, begin); - ++j; - ++begin; - } +template +It uniquify(It begin, It const end) { + std::vector v; + v.reserve(static_cast(std::distance(begin, end))); + for (It i = begin; i != end; ++i) { + v.push_back(i); + } + std::sort(v.begin(), v.end(), target_less()); + v.erase(std::unique(v.begin(), v.end(), target_equal()), v.end()); + std::sort(v.begin(), v.end()); + size_t j = 0; + for (It i = begin; i != end && j != v.size(); ++i) { + if (i == v[j]) { + using std::iter_swap; + iter_swap(i, begin); + ++j; + ++begin; } - return begin; } + return begin; +} - class RelevantTrace { - public: - bool device; - string_o deviceLabel; - StorageType storageType = StorageType::Voltage; - int_o index1; - int_o index2; - int_o sourceIndex; - int_o variableIndex; - int64_t fIndex = -1; +class RelevantTrace { + public: + bool device; + string_o deviceLabel; + StorageType storageType = StorageType::Voltage; + int_o index1; + int_o index2; + int_o sourceIndex; + int_o variableIndex; + int64_t fIndex = -1; - RelevantTrace() : - device(false) {}; - }; // class RelevantTrace + RelevantTrace() : device(false){}; +}; // class RelevantTrace - void find_relevant_traces(Input& iObj, Matrix& mObj); - void handle_current(const std::string& s, Matrix& mObj, int64_t fIndex); - void handle_voltage_or_phase( - const std::string& s, bool voltage, Matrix& mObj, int64_t fIndex); +void find_relevant_traces(Input& iObj, Matrix& mObj); +void handle_current(const std::string& s, Matrix& mObj, int64_t fIndex); +void handle_voltage_or_phase(const std::string& s, bool voltage, Matrix& mObj, + int64_t fIndex); -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Resistor.hpp b/include/JoSIM/Resistor.hpp index 6e12e013..fb245597 100644 --- a/include/JoSIM/Resistor.hpp +++ b/include/JoSIM/Resistor.hpp @@ -3,56 +3,54 @@ #ifndef JOSIM_RESISTOR_HPP #define JOSIM_RESISTOR_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Function.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/Input.hpp" #include "JoSIM/Spread.hpp" -#include "JoSIM/Function.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Rlabel V⁺ V⁻ R +/* + Rlabel V⁺ V⁻ R + + V = RIo + ⎡ 0 0 1⎤ ⎡V⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜V⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 -R⎦ ⎣Io⎦ ⎣ 0⎦ - V = RIo - ⎡ 0 0 1⎤ ⎡V⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜V⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 -R⎦ ⎣Io⎦ ⎣ 0⎦ + (PHASE) + φ - R(2e/hbar)(2h/3)Io = (4/3)φn-1 - (1/3)φn-2 - (PHASE) - φ - R(2e/hbar)(2h/3)Io = (4/3)φn-1 - (1/3)φn-2 + ⎡ 0 0 1⎤ ⎡φ⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜φ⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 -R(2e/hbar)(2h/3)⎦ ⎣Io⎦ ⎣ (4/3)φn-1 - (1/3)φn-2⎦ +*/ - ⎡ 0 0 1⎤ ⎡φ⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜φ⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 -R(2e/hbar)(2h/3)⎦ ⎣Io⎦ ⎣ (4/3)φn-1 - (1/3)φn-2⎦ - */ +class Resistor : public BasicComponent { + private: + JoSIM::AnalysisType at_; + std::optional spAmp_, temp_, neb_; - class Resistor : public BasicComponent { - private: - JoSIM::AnalysisType at_; - std::optional spAmp_, temp_, neb_; - public: - double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0; - std::optional thermalNoise; + public: + double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0; + std::optional thermalNoise; - Resistor( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi); + Resistor(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi); - void update_timestep(const double& factor) override; + void update_timestep(const double& factor) override; - void step_back() override { - pn2_ = pn4_; - } - }; // class Resistor + void step_back() override { pn2_ = pn4_; } +}; // class Resistor -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Simulation.hpp b/include/JoSIM/Simulation.hpp index 9dc953ef..f14c6084 100644 --- a/include/JoSIM/Simulation.hpp +++ b/include/JoSIM/Simulation.hpp @@ -3,15 +3,15 @@ #ifndef JOSIM_SIMULATION_H #define JOSIM_SIMULATION_H -#include "JoSIM/Errors.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Matrix.hpp" -#include "JoSIM/LUSolve.hpp" - #include #include +#include "JoSIM/Errors.hpp" +#include "JoSIM/LUSolve.hpp" +#include "JoSIM/Matrix.hpp" +#include "JoSIM/Misc.hpp" + namespace JoSIM { #define TRANSIENT 0 @@ -20,53 +20,52 @@ namespace JoSIM { #define PHASE 3 #define NONE_SPECIFIED 4 +class Results { + public: + std::vector>> xVector; + std::vector timeAxis; +}; - class Results { - public: - std::vector>> xVector; - std::vector timeAxis; - }; - - class Simulation { - private: - bool SLU = false; - std::vector x_, b_; - int64_t simSize_; - JoSIM::AnalysisType atyp_; - bool minOut_; - bool needsLU_; - bool needsTR_ = true; - bool startup_; - double stepSize_, prstep_, prstart_; - int64_t simOK_; - klu_l_symbolic* Symbolic_; - klu_l_common Common_; - klu_l_numeric* Numeric_; - LUSolve lu; +class Simulation { + private: + bool SLU = false; + std::vector x_, b_; + int64_t simSize_; + JoSIM::AnalysisType atyp_; + bool minOut_; + bool needsLU_; + bool needsTR_ = true; + bool startup_; + double stepSize_, prstep_, prstart_; + int64_t simOK_; + klu_l_symbolic* Symbolic_; + klu_l_common Common_; + klu_l_numeric* Numeric_; + LUSolve lu; - void setup(Input& iObj, Matrix& mObj); - void trans_sim(Matrix& mObj); - void setup_b(Matrix& mObj, int64_t i, double step, double factor = 1); - void reduce_step(Input& iObj, Matrix& mObj); + void setup(Input& iObj, Matrix& mObj); + void trans_sim(Matrix& mObj); + void setup_b(Matrix& mObj, int64_t i, double step, double factor = 1); + void reduce_step(Input& iObj, Matrix& mObj); - void handle_cs(Matrix& mObj, double& step, const int64_t& i); - void handle_resistors(Matrix& mObj, double& step); - void handle_inductors(Matrix& mObj, double factor = 1); - void handle_capacitors(Matrix& mObj); - void handle_jj(Matrix& mObj, int64_t& i, double& step, double factor = 1); - void handle_vs( - Matrix& mObj, const int64_t& i, double& step, double factor = 1); - void handle_ps( - Matrix& mObj, const int64_t& i, double& step, double factor = 1); - void handle_ccvs(Matrix& mObj); - void handle_vccs(Matrix& mObj); - void handle_tx( - Matrix& mObj, const int64_t& i, double& step, double factor = 1); + void handle_cs(Matrix& mObj, double& step, const int64_t& i); + void handle_resistors(Matrix& mObj, double& step); + void handle_inductors(Matrix& mObj, double factor = 1); + void handle_capacitors(Matrix& mObj); + void handle_jj(Matrix& mObj, int64_t& i, double& step, double factor = 1); + void handle_vs(Matrix& mObj, const int64_t& i, double& step, + double factor = 1); + void handle_ps(Matrix& mObj, const int64_t& i, double& step, + double factor = 1); + void handle_ccvs(Matrix& mObj); + void handle_vccs(Matrix& mObj); + void handle_tx(Matrix& mObj, const int64_t& i, double& step, + double factor = 1); - public: - Results results; + public: + Results results; - Simulation(Input& iObj, Matrix& mObj); - }; -} // namespace JoSIM + Simulation(Input& iObj, Matrix& mObj); +}; +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Spread.hpp b/include/JoSIM/Spread.hpp index 6b77fbef..84243add 100644 --- a/include/JoSIM/Spread.hpp +++ b/include/JoSIM/Spread.hpp @@ -7,20 +7,18 @@ namespace JoSIM { - class Spread { - private: - double gspread_ = 1.0, lspread_ = 1.0, rspread_ = 1.0, - cspread_ = 1.0, bspread_ = 1.0; +class Spread { + private: + double gspread_ = 1.0, lspread_ = 1.0, rspread_ = 1.0, cspread_ = 1.0, + bspread_ = 1.0; - public: - Spread() {} - void get_spreads(Input& iObj); - double spread_value(double value, int64_t type = GLB, double spread = 1.0); - enum { - GLB, RES, IND, CAP, JJ - }; - }; + public: + Spread() {} + void get_spreads(Input& iObj); + double spread_value(double value, int64_t type = GLB, double spread = 1.0); + enum { GLB, RES, IND, CAP, JJ }; +}; -} +} // namespace JoSIM -#endif // JOSIM_SPREAD_HPP \ No newline at end of file +#endif // JOSIM_SPREAD_HPP \ No newline at end of file diff --git a/include/JoSIM/Transient.hpp b/include/JoSIM/Transient.hpp index 716ac5ce..4df0bdf1 100644 --- a/include/JoSIM/Transient.hpp +++ b/include/JoSIM/Transient.hpp @@ -3,65 +3,44 @@ #ifndef JOSIM_TRANSIENT_HPP #define JOSIM_TRANSIENT_HPP -#include "JoSIM/TypeDefines.hpp" - #include #include +#include "JoSIM/TypeDefines.hpp" + namespace JoSIM { - class Transient { - private: - double tstep_; - double tstop_; - double prstart_; - double prstep_; - bool startup_; - public: - Transient() : - tstep_(0.25E-12), - tstop_(0.0), - prstart_(0.0), - prstep_(1E-12), - startup_(true) {}; +class Transient { + private: + double tstep_; + double tstop_; + double prstart_; + double prstep_; + bool startup_; + + public: + Transient() + : tstep_(0.25E-12), + tstop_(0.0), + prstart_(0.0), + prstep_(1E-12), + startup_(true){}; - double tstep() const { - return tstep_; - } - double tstop() const { - return tstop_; - } - double prstart() const { - return prstart_; - } - double prstep() const { - return prstep_; - } - int64_t simsize() const { - return static_cast(tstop_ / tstep_); - } - bool startup() const { - return startup_; - } + double tstep() const { return tstep_; } + double tstop() const { return tstop_; } + double prstart() const { return prstart_; } + double prstep() const { return prstep_; } + int64_t simsize() const { return static_cast(tstop_ / tstep_); } + bool startup() const { return startup_; } - void tstep(double value) { - tstep_ = value; - } - void tstop(double value) { - tstop_ = value; - } - void prstart(double value) { - prstart_ = value; - } - void prstep(double value) { - prstep_ = value; - } - void startup(bool value) { - startup_ = value; - } + void tstep(double value) { tstep_ = value; } + void tstop(double value) { tstop_ = value; } + void prstart(double value) { prstart_ = value; } + void prstep(double value) { prstep_ = value; } + void startup(bool value) { startup_ = value; } - static void identify_simulation( - std::vector& controls, Transient& tObj); - }; -} + static void identify_simulation(std::vector& controls, + Transient& tObj); +}; +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/TransmissionLine.hpp b/include/JoSIM/TransmissionLine.hpp index 32d539df..c30ea338 100644 --- a/include/JoSIM/TransmissionLine.hpp +++ b/include/JoSIM/TransmissionLine.hpp @@ -3,78 +3,80 @@ #ifndef JOSIM_TRANSMISSIONLINE_HPP #define JOSIM_TRANSMISSIONLINE_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Tlabel Vi⁺ Vi⁻ Vo⁺ Vo⁻ td=value z0=value - - V1 - ZI1 = ZI2n-k + V2n-k - V2 - ZI2 = ZI1n-k + V1n-k - - k = td/h - - ⎡ 0 0 0 0 1 0⎤ ⎡V1⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 -1 0⎟ ⎜V1⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 0 1⎟ ⎜V2⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 0 -1⎟ ⎜V2⁻⎟ ⎜ 0⎟ - ⎜ 1 -1 0 0 -Z 0⎟ ⎜I1 ⎟ ⎜ ZI2n-k + V2n-k⎟ - ⎣ 0 0 1 -1 0 -Z⎦ ⎣I2 ⎦ ⎣ ZI1n-k + V1n-k⎦ - - (PHASE) - φ1 - Z(2e/hbar)(2h/3)I1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + - φ2n-k - (4/3)φ2n-k-1 + (1/3)φ2n-k-2 - φ2 - Z(2e/hbar)(2h/3)I2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + - φ1n-k - (4/3)φ1n-k-1 + (1/3)φ1n-k-2 - - ⎡ 0 0 0 0 -1 0⎤ ⎡φo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 1 0⎟ ⎜φo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 0 1⎟ ⎜φc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 0 -1⎟ ⎜φc⁻⎟ ⎜ 0⎟ - ⎜ 1 -1 0 0 -Z(2e/hbar)(2h/3) 0⎟ ⎜Ic ⎟ ⎜ RHS1⎟ - ⎣ 0 0 1 -1 0 -Z(2e/hbar)(2h/3)⎦ ⎣Io ⎦ ⎣ RHS2⎦ - - RHS1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + - φ2n-k - (4/3)φ2n-k-1 + (1/3)φ2n-k-2 - RHS2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + - φ1n-k - (4/3)φ1n-k-1 + (1/3)φ1n-k-2 - */ - - class TransmissionLine : public BasicComponent { - private: - int64_t hDepPos_ = 0; - JoSIM::AnalysisType at_; - public: - NodeConfig nodeConfig2_; - int_o posIndex2_, negIndex2_; - int64_t currentIndex2_ = 0; - double n1_1_ = 0.0, n1_2_ = 0.0, n2_1_ = 0.0, n2_2_ = 0.0; - double nk_1_ = 0.0, nk_2_ = 0.0, nk1_1_ = 0.0, nk1_2_ = 0.0, nk2_1_ = 0.0, - nk2_2_ = 0.0; - int64_t timestepDelay_ = 0; - - TransmissionLine( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, const AnalysisType& at, const double& h, int64_t& bi); - - void set_secondary_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc); - void set_secondary_matrix_info(); - - void update_timestep(const double& factor) override; - }; // class TransmissionLine - -} // namespace JoSIM +/* + Tlabel Vi⁺ Vi⁻ Vo⁺ Vo⁻ td=value z0=value + + V1 - ZI1 = ZI2n-k + V2n-k + V2 - ZI2 = ZI1n-k + V1n-k + + k = td/h + + ⎡ 0 0 0 0 1 0⎤ ⎡V1⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 -1 0⎟ ⎜V1⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 0 1⎟ ⎜V2⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 0 -1⎟ ⎜V2⁻⎟ ⎜ 0⎟ + ⎜ 1 -1 0 0 -Z 0⎟ ⎜I1 ⎟ ⎜ ZI2n-k + V2n-k⎟ + ⎣ 0 0 1 -1 0 -Z⎦ ⎣I2 ⎦ ⎣ ZI1n-k + V1n-k⎦ + + (PHASE) + φ1 - Z(2e/hbar)(2h/3)I1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + + φ2n-k - (4/3)φ2n-k-1 + (1/3)φ2n-k-2 + φ2 - Z(2e/hbar)(2h/3)I2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + + φ1n-k - (4/3)φ1n-k-1 + (1/3)φ1n-k-2 + + ⎡ 0 0 0 0 -1 0⎤ ⎡φo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 1 0⎟ ⎜φo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 0 1⎟ ⎜φc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 0 -1⎟ ⎜φc⁻⎟ ⎜ 0⎟ + ⎜ 1 -1 0 0 -Z(2e/hbar)(2h/3) 0⎟ ⎜Ic ⎟ ⎜ RHS1⎟ + ⎣ 0 0 1 -1 0 -Z(2e/hbar)(2h/3)⎦ ⎣Io ⎦ ⎣ RHS2⎦ + + RHS1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + + φ2n-k - (4/3)φ2n-k-1 + (1/3)φ2n-k-2 + RHS2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + + φ1n-k - (4/3)φ1n-k-1 + (1/3)φ1n-k-2 +*/ + +class TransmissionLine : public BasicComponent { + private: + int64_t hDepPos_ = 0; + JoSIM::AnalysisType at_; + + public: + NodeConfig nodeConfig2_; + int_o posIndex2_, negIndex2_; + int64_t currentIndex2_ = 0; + double n1_1_ = 0.0, n1_2_ = 0.0, n2_1_ = 0.0, n2_2_ = 0.0; + double nk_1_ = 0.0, nk_2_ = 0.0, nk1_1_ = 0.0, nk1_2_ = 0.0, nk2_1_ = 0.0, + nk2_2_ = 0.0; + int64_t timestepDelay_ = 0; + + TransmissionLine(const std::pair& s, + const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, const AnalysisType& at, const double& h, + int64_t& bi); + + void set_secondary_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc); + void set_secondary_matrix_info(); + + void update_timestep(const double& factor) override; +}; // class TransmissionLine + +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/TypeDefines.hpp b/include/JoSIM/TypeDefines.hpp index cea2f1d7..0615c5a9 100644 --- a/include/JoSIM/TypeDefines.hpp +++ b/include/JoSIM/TypeDefines.hpp @@ -3,25 +3,25 @@ #ifndef JOSIM_TYPEDEFINES_HPP #define JOSIM_TYPEDEFINES_HPP +#include #include #include -#include namespace JoSIM { - // Define a type that specifies tokens - using tokens_t = std::vector; +// Define a type that specifies tokens +using tokens_t = std::vector; - // Define types to shorthand optional types - using string_o = std::optional; - using char_o = std::optional; - using double_o = std::optional; - using int_o = std::optional; +// Define types to shorthand optional types +using string_o = std::optional; +using char_o = std::optional; +using double_o = std::optional; +using int_o = std::optional; - // Define a type that is a vector of pairs of type T1 and T2 - template - using vector_pair_t = std::vector>; +// Define a type that is a vector of pairs of type T1 and T2 +template +using vector_pair_t = std::vector>; -} // namespace JoSIM +} // namespace JoSIM -#endif // JOSIM_TYPEDEFINES_HPP +#endif // JOSIM_TYPEDEFINES_HPP diff --git a/include/JoSIM/VCCS.hpp b/include/JoSIM/VCCS.hpp index d6cd846d..ff8c6844 100644 --- a/include/JoSIM/VCCS.hpp +++ b/include/JoSIM/VCCS.hpp @@ -3,65 +3,63 @@ #ifndef JOSIM_VCCS_HPP #define JOSIM_VCCS_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/Input.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Glabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G +/* + Glabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G - Io = GVc + Io = GVc - ⎡ 0 0 0 0 1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 -1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 0⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 0⎟ ⎜Vc⁻⎟ ⎜ 0⎟ - ⎣ 0 0 1 -1 -1/G⎦ ⎣Io ⎦ ⎣ 0⎦ + ⎡ 0 0 0 0 1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 -1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 0⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 0⎟ ⎜Vc⁻⎟ ⎜ 0⎟ + ⎣ 0 0 1 -1 -1/G⎦ ⎣Io ⎦ ⎣ 0⎦ - (PHASE) - φ - (2e/hbar)(2h/3G)Io = (4/3)φn-1 - (1/3)φn-2 + (PHASE) + φ - (2e/hbar)(2h/3G)Io = (4/3)φn-1 - (1/3)φn-2 - ⎡ 0 0 0 0 1⎤ ⎡φo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 -1⎟ ⎜φo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 0⎟ ⎜φc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 0⎟ ⎜φc⁻⎟ ⎜ 0⎟ - ⎣ 0 0 1 -1 -(2e/hbar)(2h/3G)⎦ ⎣Io ⎦ ⎣ (4/3)φn-1 - (1/3)φn-2⎦ - */ + ⎡ 0 0 0 0 1⎤ ⎡φo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 -1⎟ ⎜φo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 0⎟ ⎜φc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 0⎟ ⎜φc⁻⎟ ⎜ 0⎟ + ⎣ 0 0 1 -1 -(2e/hbar)(2h/3G)⎦ ⎣Io ⎦ ⎣ (4/3)φn-1 - (1/3)φn-2⎦ +*/ +class VCCS : public BasicComponent { + private: + JoSIM::AnalysisType at_; - class VCCS : public BasicComponent { - private: - JoSIM::AnalysisType at_; - public: - NodeConfig nodeConfig2_; - int_o posIndex2_, negIndex2_; - double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0; + public: + NodeConfig nodeConfig2_; + int_o posIndex2_, negIndex2_; + double pn1_ = 0.0, pn2_ = 0.0, pn3_ = 0.0, pn4_ = 0.0; - VCCS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi, const AnalysisType& at, const double& h); + VCCS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi, const AnalysisType& at, + const double& h); - void set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc); - void set_matrix_info(); + void set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc); + void set_matrix_info(); - void update_timestep(const double& factor) override; + void update_timestep(const double& factor) override; - void step_back() override { - pn2_ = pn4_; - } - }; // class VCCS + void step_back() override { pn2_ = pn4_; } +}; // class VCCS -} // namespace JoSIM +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/VCVS.hpp b/include/JoSIM/VCVS.hpp index 6c5a6642..d86b6715 100644 --- a/include/JoSIM/VCVS.hpp +++ b/include/JoSIM/VCVS.hpp @@ -3,44 +3,43 @@ #ifndef JOSIM_VCVS_HPP #define JOSIM_VCVS_HPP +#include +#include +#include +#include + +#include "JoSIM/AnalysisType.hpp" #include "JoSIM/BasicComponent.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/AnalysisType.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Elabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G - - Vo = GVc - ⎡ 0 0 0 0 -1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ - ⎜ 0 0 0 0 1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ - ⎜ 0 0 0 0 0⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ - ⎜ 0 0 0 0 0⎟ ⎜Vc⁻⎟ ⎜ 0⎟ - ⎣-1 1 G -G 0⎦ ⎣Io ⎦ ⎣ 0⎦ - */ - - class VCVS : public BasicComponent { - public: - NodeConfig nodeConfig2_; - int_o posIndex2_, negIndex2_; - - VCVS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi); - - void set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc); - void set_matrix_info(); - }; // class VCVS - -} // namespace JoSIM +/* + Elabel Vo⁺ Vo⁻ Vc⁺ Vc⁻ G + + Vo = GVc + ⎡ 0 0 0 0 -1⎤ ⎡Vo⁺⎤ ⎡ 0⎤ + ⎜ 0 0 0 0 1⎟ ⎜Vo⁻⎟ ⎜ 0⎟ + ⎜ 0 0 0 0 0⎟ ⎜Vc⁺⎟ = ⎜ 0⎟ + ⎜ 0 0 0 0 0⎟ ⎜Vc⁻⎟ ⎜ 0⎟ + ⎣-1 1 G -G 0⎦ ⎣Io ⎦ ⎣ 0⎦ +*/ + +class VCVS : public BasicComponent { + public: + NodeConfig nodeConfig2_; + int_o posIndex2_, negIndex2_; + + VCVS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi); + + void set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc); + void set_matrix_info(); +}; // class VCVS + +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/JoSIM/Verbose.hpp b/include/JoSIM/Verbose.hpp index 12ff2e1b..6711c08a 100644 --- a/include/JoSIM/Verbose.hpp +++ b/include/JoSIM/Verbose.hpp @@ -3,26 +3,25 @@ #ifndef JOSIM_VERBOSE_HPP #define JOSIM_VERBOSE_HPP -#include "JoSIM/TypeDefines.hpp" -#include "JoSIM/Input.hpp" -#include "JoSIM/Matrix.hpp" - #include #include +#include "JoSIM/Input.hpp" +#include "JoSIM/Matrix.hpp" +#include "JoSIM/TypeDefines.hpp" + namespace JoSIM { - namespace Verbose { - void handle_verbosity( - const int64_t& vl, const Input& iObj, const Matrix& mObj); +namespace Verbose { +void handle_verbosity(const int64_t& vl, const Input& iObj, const Matrix& mObj); - void print_circuit_stats(const Input& iObj, const Matrix& mObj); +void print_circuit_stats(const Input& iObj, const Matrix& mObj); - void print_parameters(const Input& iObj); +void print_parameters(const Input& iObj); - void print_expanded_netlist(const Input& iObj); - } // namespace Verbose +void print_expanded_netlist(const Input& iObj); +} // namespace Verbose -} // namespace JoSIM +} // namespace JoSIM #endif diff --git a/include/JoSIM/VoltageSource.hpp b/include/JoSIM/VoltageSource.hpp index b5ccf782..6301549c 100644 --- a/include/JoSIM/VoltageSource.hpp +++ b/include/JoSIM/VoltageSource.hpp @@ -3,39 +3,36 @@ #ifndef JOSIM_VOLTAGESOURCE_HPP #define JOSIM_VOLTAGESOURCE_HPP +#include +#include +#include +#include + #include "JoSIM/BasicComponent.hpp" +#include "JoSIM/Function.hpp" #include "JoSIM/ParameterName.hpp" #include "JoSIM/Parameters.hpp" -#include "JoSIM/Function.hpp" - -#include -#include -#include -#include namespace JoSIM { - /* - Vlabel V⁺ V⁻ sourcetype - - ⎡ 0 0 1⎤ ⎡V⁺⎤ ⎡ 0⎤ - ⎜ 0 0 -1⎟ ⎜V⁻⎟ = ⎜ 0⎟ - ⎣ 1 -1 0⎦ ⎣Io⎦ ⎣ 0⎦ - */ - - class VoltageSource : public BasicComponent { - public: - int64_t sourceIndex_; - double pn1_ = 0.0, pn2_ = pn1_, pn3_ = pn2_, pn4_ = 0.0; - VoltageSource( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, int64_t& bi, const int64_t& ci); - - void step_back() override { - pn2_ = pn4_; - } - }; // class VoltageSource - -} // namespace JoSIM +/* + Vlabel V⁺ V⁻ sourcetype + + ⎡ 0 0 1⎤ ⎡V⁺⎤ ⎡ 0⎤ + ⎜ 0 0 -1⎟ ⎜V⁻⎟ = ⎜ 0⎟ + ⎣ 1 -1 0⎦ ⎣Io⎦ ⎣ 0⎦ +*/ + +class VoltageSource : public BasicComponent { + public: + int64_t sourceIndex_; + double pn1_ = 0.0, pn2_ = pn1_, pn3_ = pn2_, pn4_ = 0.0; + VoltageSource(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, int64_t& bi, const int64_t& ci); + + void step_back() override { pn2_ = pn4_; } +}; // class VoltageSource + +} // namespace JoSIM #endif \ No newline at end of file diff --git a/include/spline.h b/include/spline.h index b9e707ab..614119ec 100644 --- a/include/spline.h +++ b/include/spline.h @@ -23,19 +23,18 @@ * */ - #ifndef TK_SPLINE_H #define TK_SPLINE_H -#include +#include #include #include +#include #include -#include #ifdef HAVE_SSTREAM #include #include -#endif // HAVE_SSTREAM +#endif // HAVE_SSTREAM // not ideal but disable unused-function warnings // (we get them because we have implementations in the header file, @@ -46,148 +45,134 @@ // unnamed namespace only because the implementation is in this // header file and we don't want to export symbols to the obj files -namespace -{ +namespace { -namespace tk -{ +namespace tk { // spline interpolation -class spline -{ -public: - // spline types - enum spline_type { - linear = 10, // linear interpolation - cspline = 30, // cubic splines (classical C^2) - cspline_hermite = 31 // cubic hermite splines (local, only C^1) - }; - - // boundary condition type for the spline end-points - enum bd_type { - first_deriv = 1, - second_deriv = 2 - }; - -protected: - std::vector m_x,m_y; // x,y coordinates of points - // interpolation parameters - // f(x) = a_i + b_i*(x-x_i) + c_i*(x-x_i)^2 + d_i*(x-x_i)^3 - // where a_i = y_i, or else it won't go through grid points - std::vector m_b,m_c,m_d; // spline coefficients - double m_c0; // for left extrapolation - spline_type m_type; - bd_type m_left, m_right; - double m_left_value, m_right_value; - bool m_made_monotonic; - void set_coeffs_from_b(); // calculate c_i, d_i from b_i - size_t find_closest(double x) const; // closest idx so that m_x[idx]<=x - -public: - // default constructor: set boundary condition to be zero curvature - // at both ends, i.e. natural splines - spline(): m_type(cspline), - m_left(second_deriv), m_right(second_deriv), - m_left_value(0.0), m_right_value(0.0), m_made_monotonic(false) - { - ; - } - spline(const std::vector& X, const std::vector& Y, - spline_type type = cspline, - bool make_monotonic = false, - bd_type left = second_deriv, double left_value = 0.0, - bd_type right = second_deriv, double right_value = 0.0 - ): - m_type(type), - m_left(left), m_right(right), - m_left_value(left_value), m_right_value(right_value), - m_made_monotonic(false) // false correct here: make_monotonic() sets it - { - this->set_points(X,Y,m_type); - if(make_monotonic) { - this->make_monotonic(); - } +class spline { + public: + // spline types + enum spline_type { + linear = 10, // linear interpolation + cspline = 30, // cubic splines (classical C^2) + cspline_hermite = 31 // cubic hermite splines (local, only C^1) + }; + + // boundary condition type for the spline end-points + enum bd_type { first_deriv = 1, second_deriv = 2 }; + + protected: + std::vector m_x, m_y; // x,y coordinates of points + // interpolation parameters + // f(x) = a_i + b_i*(x-x_i) + c_i*(x-x_i)^2 + d_i*(x-x_i)^3 + // where a_i = y_i, or else it won't go through grid points + std::vector m_b, m_c, m_d; // spline coefficients + double m_c0; // for left extrapolation + spline_type m_type; + bd_type m_left, m_right; + double m_left_value, m_right_value; + bool m_made_monotonic; + void set_coeffs_from_b(); // calculate c_i, d_i from b_i + size_t find_closest(double x) const; // closest idx so that m_x[idx]<=x + + public: + // default constructor: set boundary condition to be zero curvature + // at both ends, i.e. natural splines + spline() + : m_type(cspline), + m_left(second_deriv), + m_right(second_deriv), + m_left_value(0.0), + m_right_value(0.0), + m_made_monotonic(false) { + ; + } + spline(const std::vector& X, const std::vector& Y, + spline_type type = cspline, bool make_monotonic = false, + bd_type left = second_deriv, double left_value = 0.0, + bd_type right = second_deriv, double right_value = 0.0) + : m_type(type), + m_left(left), + m_right(right), + m_left_value(left_value), + m_right_value(right_value), + m_made_monotonic(false) // false correct here: make_monotonic() sets it + { + this->set_points(X, Y, m_type); + if (make_monotonic) { + this->make_monotonic(); } - - - // modify boundary conditions: if called it must be before set_points() - void set_boundary(bd_type left, double left_value, - bd_type right, double right_value); - - // set all data points (cubic_spline=false means linear interpolation) - void set_points(const std::vector& x, - const std::vector& y, - spline_type type=cspline); - - // adjust coefficients so that the spline becomes piecewise monotonic - // where possible - // this is done by adjusting slopes at grid points by a non-negative - // factor and this will break C^2 - // this can also break boundary conditions if adjustments need to - // be made at the boundary points - // returns false if no adjustments have been made, true otherwise - bool make_monotonic(); - - // evaluates the spline at point x - double operator() (double x) const; - double deriv(int order, double x) const; - - // returns the input data points - std::vector get_x() const { return m_x; } - std::vector get_y() const { return m_y; } - double get_x_min() const { assert(!m_x.empty()); return m_x.front(); } - double get_x_max() const { assert(!m_x.empty()); return m_x.back(); } + } + + // modify boundary conditions: if called it must be before set_points() + void set_boundary(bd_type left, double left_value, bd_type right, + double right_value); + + // set all data points (cubic_spline=false means linear interpolation) + void set_points(const std::vector& x, const std::vector& y, + spline_type type = cspline); + + // adjust coefficients so that the spline becomes piecewise monotonic + // where possible + // this is done by adjusting slopes at grid points by a non-negative + // factor and this will break C^2 + // this can also break boundary conditions if adjustments need to + // be made at the boundary points + // returns false if no adjustments have been made, true otherwise + bool make_monotonic(); + + // evaluates the spline at point x + double operator()(double x) const; + double deriv(int order, double x) const; + + // returns the input data points + std::vector get_x() const { return m_x; } + std::vector get_y() const { return m_y; } + double get_x_min() const { + assert(!m_x.empty()); + return m_x.front(); + } + double get_x_max() const { + assert(!m_x.empty()); + return m_x.back(); + } #ifdef HAVE_SSTREAM - // spline info string, i.e. spline type, boundary conditions etc. - std::string info() const; -#endif // HAVE_SSTREAM - + // spline info string, i.e. spline type, boundary conditions etc. + std::string info() const; +#endif // HAVE_SSTREAM }; - - -namespace internal -{ +namespace internal { // band matrix solver -class band_matrix -{ -private: - std::vector< std::vector > m_upper; // upper band - std::vector< std::vector > m_lower; // lower band -public: - band_matrix() {}; // constructor - band_matrix(int dim, int n_u, int n_l); // constructor - ~band_matrix() {}; // destructor - void resize(int dim, int n_u, int n_l); // init with dim,n_u,n_l - int dim() const; // matrix dimension - int num_upper() const - { - return (int)m_upper.size()-1; - } - int num_lower() const - { - return (int)m_lower.size()-1; - } - // access operator - double & operator () (int i, int j); // write - double operator () (int i, int j) const; // read - // we can store an additional diagonal (in m_lower) - double& saved_diag(int i); - double saved_diag(int i) const; - void lu_decompose(); - std::vector r_solve(const std::vector& b) const; - std::vector l_solve(const std::vector& b) const; - std::vector lu_solve(const std::vector& b, - bool is_lu_decomposed=false); - +class band_matrix { + private: + std::vector > m_upper; // upper band + std::vector > m_lower; // lower band + public: + band_matrix(){}; // constructor + band_matrix(int dim, int n_u, int n_l); // constructor + ~band_matrix(){}; // destructor + void resize(int dim, int n_u, int n_l); // init with dim,n_u,n_l + int dim() const; // matrix dimension + int num_upper() const { return (int)m_upper.size() - 1; } + int num_lower() const { return (int)m_lower.size() - 1; } + // access operator + double& operator()(int i, int j); // write + double operator()(int i, int j) const; // read + // we can store an additional diagonal (in m_lower) + double& saved_diag(int i); + double saved_diag(int i) const; + void lu_decompose(); + std::vector r_solve(const std::vector& b) const; + std::vector l_solve(const std::vector& b) const; + std::vector lu_solve(const std::vector& b, + bool is_lu_decomposed = false); }; -} // namespace internal - - - +} // namespace internal // --------------------------------------------------------------------- // implementation part, which could be separated into a cpp file @@ -197,486 +182,467 @@ class band_matrix // ----------------------- void spline::set_boundary(spline::bd_type left, double left_value, - spline::bd_type right, double right_value) -{ - assert(m_x.size()==0); // set_points() must not have happened yet - m_left=left; - m_right=right; - m_left_value=left_value; - m_right_value=right_value; + spline::bd_type right, double right_value) { + assert(m_x.size() == 0); // set_points() must not have happened yet + m_left = left; + m_right = right; + m_left_value = left_value; + m_right_value = right_value; } - -void spline::set_coeffs_from_b() -{ - assert(m_x.size()==m_y.size()); - assert(m_x.size()==m_b.size()); - assert(m_x.size()>2); - size_t n=m_b.size(); - if(m_c.size()!=n) - m_c.resize(n); - if(m_d.size()!=n) - m_d.resize(n); - - for(size_t i=0; i 2); + size_t n = m_b.size(); + if (m_c.size() != n) m_c.resize(n); + if (m_d.size() != n) m_d.resize(n); + + for (size_t i = 0; i < n - 1; i++) { + const double h = m_x[i + 1] - m_x[i]; + // from continuity and differentiability condition + m_c[i] = + (3.0 * (m_y[i + 1] - m_y[i]) / h - (2.0 * m_b[i] + m_b[i + 1])) / h; + // from differentiability condition + m_d[i] = ((m_b[i + 1] - m_b[i]) / (3.0 * h) - 2.0 / 3.0 * m_c[i]) / h; + } + + // for left extrapolation coefficients + m_c0 = (m_left == first_deriv) ? 0.0 : m_c[0]; } void spline::set_points(const std::vector& x, - const std::vector& y, - spline_type type) -{ - assert(x.size()==y.size()); - assert(x.size()>2); - m_type=type; - m_made_monotonic=false; - m_x=x; - m_y=y; - int n = (int) x.size(); - // check strict monotonicity of input vector x - for(int i=0; i& y, spline_type type) { + assert(x.size() == y.size()); + assert(x.size() > 2); + m_type = type; + m_made_monotonic = false; + m_x = x; + m_y = y; + int n = (int)x.size(); + // check strict monotonicity of input vector x + for (int i = 0; i < n - 1; i++) { + assert(m_x[i] < m_x[i + 1]); + } + + if (type == linear) { + // linear interpolation + m_d.resize(n); + m_c.resize(n); + m_b.resize(n); + for (int i = 0; i < n - 1; i++) { + m_d[i] = 0.0; + m_c[i] = 0.0; + m_b[i] = (m_y[i + 1] - m_y[i]) / (m_x[i + 1] - m_x[i]); + } + // ignore boundary conditions, set slope equal to the last segment + m_b[n - 1] = m_b[n - 2]; + m_c[n - 1] = 0.0; + m_d[n - 1] = 0.0; + } else if (type == cspline) { + // classical cubic splines which are C^2 (twice cont differentiable) + // this requires solving an equation system + + // setting up the matrix and right hand side of the equation system + // for the parameters b[] + internal::band_matrix A(n, 1, 1); + std::vector rhs(n); + for (int i = 1; i < n - 1; i++) { + A(i, i - 1) = 1.0 / 3.0 * (x[i] - x[i - 1]); + A(i, i) = 2.0 / 3.0 * (x[i + 1] - x[i - 1]); + A(i, i + 1) = 1.0 / 3.0 * (x[i + 1] - x[i]); + rhs[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - + (y[i] - y[i - 1]) / (x[i] - x[i - 1]); + } + // boundary conditions + if (m_left == spline::second_deriv) { + // 2*c[0] = f'' + A(0, 0) = 2.0; + A(0, 1) = 0.0; + rhs[0] = m_left_value; + } else if (m_left == spline::first_deriv) { + // b[0] = f', needs to be re-expressed in terms of c: + // (2c[0]+c[1])(x[1]-x[0]) = 3 ((y[1]-y[0])/(x[1]-x[0]) - f') + A(0, 0) = 2.0 * (x[1] - x[0]); + A(0, 1) = 1.0 * (x[1] - x[0]); + rhs[0] = 3.0 * ((y[1] - y[0]) / (x[1] - x[0]) - m_left_value); + } else { + assert(false); + } + if (m_right == spline::second_deriv) { + // 2*c[n-1] = f'' + A(n - 1, n - 1) = 2.0; + A(n - 1, n - 2) = 0.0; + rhs[n - 1] = m_right_value; + } else if (m_right == spline::first_deriv) { + // b[n-1] = f', needs to be re-expressed in terms of c: + // (c[n-2]+2c[n-1])(x[n-1]-x[n-2]) + // = 3 (f' - (y[n-1]-y[n-2])/(x[n-1]-x[n-2])) + A(n - 1, n - 1) = 2.0 * (x[n - 1] - x[n - 2]); + A(n - 1, n - 2) = 1.0 * (x[n - 1] - x[n - 2]); + rhs[n - 1] = + 3.0 * (m_right_value - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2])); + } else { + assert(false); } + // solve the equation system to obtain the parameters c[] + m_c = A.lu_solve(rhs); - if(type==linear) { - // linear interpolation - m_d.resize(n); - m_c.resize(n); - m_b.resize(n); - for(int i=0; i rhs(n); - for(int i=1; i2); - bool modified = false; - const int n=(int)m_x.size(); - // make sure: input data monotonic increasing --> b_i>=0 - // input data monotonic decreasing --> b_i<=0 - for(int i=0; i=m_y[i]) && (m_y[i]>=m_y[ip1]) && m_b[i]>0.0) ) { - modified=true; - m_b[i]=0.0; - } +bool spline::make_monotonic() { + assert(m_x.size() == m_y.size()); + assert(m_x.size() == m_b.size()); + assert(m_x.size() > 2); + bool modified = false; + const int n = (int)m_x.size(); + // make sure: input data monotonic increasing --> b_i>=0 + // input data monotonic decreasing --> b_i<=0 + for (int i = 0; i < n; i++) { + int im1 = std::max(i - 1, 0); + int ip1 = std::min(i + 1, n - 1); + if (((m_y[im1] <= m_y[i]) && (m_y[i] <= m_y[ip1]) && m_b[i] < 0.0) || + ((m_y[im1] >= m_y[i]) && (m_y[i] >= m_y[ip1]) && m_b[i] > 0.0)) { + modified = true; + m_b[i] = 0.0; } - // if input data is monotonic (b[i], b[i+1], avg have all the same sign) - // ensure a sufficient criteria for monotonicity is satisfied: - // sqrt(b[i]^2+b[i+1]^2) <= 3 |avg|, with avg=(y[i+1]-y[i])/h, - for(int i=0; i=0.0 && m_b[i+1]>=0.0 && avg>0.0) || - (m_b[i]<=0.0 && m_b[i+1]<=0.0 && avg<0.0) ) { - // input data is monotonic - double r = sqrt(m_b[i]*m_b[i]+m_b[i+1]*m_b[i+1])/std::fabs(avg); - if(r>3.0) { - // sufficient criteria for monotonicity: r<=3 - // adjust b[i] and b[i+1] - modified=true; - m_b[i] *= (3.0/r); - m_b[i+1] *= (3.0/r); - } - } + } + // if input data is monotonic (b[i], b[i+1], avg have all the same sign) + // ensure a sufficient criteria for monotonicity is satisfied: + // sqrt(b[i]^2+b[i+1]^2) <= 3 |avg|, with avg=(y[i+1]-y[i])/h, + for (int i = 0; i < n - 1; i++) { + double h = m_x[i + 1] - m_x[i]; + double avg = (m_y[i + 1] - m_y[i]) / h; + if (avg == 0.0 && (m_b[i] != 0.0 || m_b[i + 1] != 0.0)) { + modified = true; + m_b[i] = 0.0; + m_b[i + 1] = 0.0; + } else if ((m_b[i] >= 0.0 && m_b[i + 1] >= 0.0 && avg > 0.0) || + (m_b[i] <= 0.0 && m_b[i + 1] <= 0.0 && avg < 0.0)) { + // input data is monotonic + double r = + sqrt(m_b[i] * m_b[i] + m_b[i + 1] * m_b[i + 1]) / std::fabs(avg); + if (r > 3.0) { + // sufficient criteria for monotonicity: r<=3 + // adjust b[i] and b[i+1] + modified = true; + m_b[i] *= (3.0 / r); + m_b[i + 1] *= (3.0 / r); + } } + } - if(modified==true) { - set_coeffs_from_b(); - m_made_monotonic=true; - } + if (modified == true) { + set_coeffs_from_b(); + m_made_monotonic = true; + } - return modified; + return modified; } // return the closest idx so that m_x[idx] <= x (return 0 if x::const_iterator it; - it=std::upper_bound(m_x.begin(),m_x.end(),x); // *it > x - size_t idx = std::max( int(it-m_x.begin())-1, 0); // m_x[idx] <= x - return idx; +size_t spline::find_closest(double x) const { + std::vector::const_iterator it; + it = std::upper_bound(m_x.begin(), m_x.end(), x); // *it > x + size_t idx = std::max(int(it - m_x.begin()) - 1, 0); // m_x[idx] <= x + return idx; } -double spline::operator() (double x) const -{ - // polynomial evaluation using Horner's scheme - // TODO: consider more numerically accurate algorithms, e.g.: - // - Clenshaw - // - Even-Odd method by A.C.R. Newbery - // - Compensated Horner Scheme - size_t n=m_x.size(); - size_t idx=find_closest(x); - - double h=x-m_x[idx]; - double interpol; - if(xm_x[n-1]) { - // extrapolation to the right - interpol=(m_c[n-1]*h + m_b[n-1])*h + m_y[n-1]; - } else { - // interpolation - interpol=((m_d[idx]*h + m_c[idx])*h + m_b[idx])*h + m_y[idx]; - } - return interpol; +double spline::operator()(double x) const { + // polynomial evaluation using Horner's scheme + // TODO: consider more numerically accurate algorithms, e.g.: + // - Clenshaw + // - Even-Odd method by A.C.R. Newbery + // - Compensated Horner Scheme + size_t n = m_x.size(); + size_t idx = find_closest(x); + + double h = x - m_x[idx]; + double interpol; + if (x < m_x[0]) { + // extrapolation to the left + interpol = (m_c0 * h + m_b[0]) * h + m_y[0]; + } else if (x > m_x[n - 1]) { + // extrapolation to the right + interpol = (m_c[n - 1] * h + m_b[n - 1]) * h + m_y[n - 1]; + } else { + // interpolation + interpol = ((m_d[idx] * h + m_c[idx]) * h + m_b[idx]) * h + m_y[idx]; + } + return interpol; } -double spline::deriv(int order, double x) const -{ - assert(order>0); - size_t n=m_x.size(); - size_t idx = find_closest(x); - - double h=x-m_x[idx]; - double interpol; - if(xm_x[n-1]) { - // extrapolation to the right - switch(order) { - case 1: - interpol=2.0*m_c[n-1]*h + m_b[n-1]; - break; - case 2: - interpol=2.0*m_c[n-1]; - break; - default: - interpol=0.0; - break; - } - } else { - // interpolation - switch(order) { - case 1: - interpol=(3.0*m_d[idx]*h + 2.0*m_c[idx])*h + m_b[idx]; - break; - case 2: - interpol=6.0*m_d[idx]*h + 2.0*m_c[idx]; - break; - case 3: - interpol=6.0*m_d[idx]; - break; - default: - interpol=0.0; - break; - } +double spline::deriv(int order, double x) const { + assert(order > 0); + size_t n = m_x.size(); + size_t idx = find_closest(x); + + double h = x - m_x[idx]; + double interpol; + if (x < m_x[0]) { + // extrapolation to the left + switch (order) { + case 1: + interpol = 2.0 * m_c0 * h + m_b[0]; + break; + case 2: + interpol = 2.0 * m_c0; + break; + default: + interpol = 0.0; + break; + } + } else if (x > m_x[n - 1]) { + // extrapolation to the right + switch (order) { + case 1: + interpol = 2.0 * m_c[n - 1] * h + m_b[n - 1]; + break; + case 2: + interpol = 2.0 * m_c[n - 1]; + break; + default: + interpol = 0.0; + break; + } + } else { + // interpolation + switch (order) { + case 1: + interpol = (3.0 * m_d[idx] * h + 2.0 * m_c[idx]) * h + m_b[idx]; + break; + case 2: + interpol = 6.0 * m_d[idx] * h + 2.0 * m_c[idx]; + break; + case 3: + interpol = 6.0 * m_d[idx]; + break; + default: + interpol = 0.0; + break; } - return interpol; + } + return interpol; } #ifdef HAVE_SSTREAM -std::string spline::info() const -{ - std::stringstream ss; - ss << "type " << m_type << ", left boundary deriv " << m_left << " = "; - ss << m_left_value << ", right boundary deriv " << m_right << " = "; - ss << m_right_value << std::endl; - if(m_made_monotonic) { - ss << "(spline has been adjusted for piece-wise monotonicity)"; - } - return ss.str(); +std::string spline::info() const { + std::stringstream ss; + ss << "type " << m_type << ", left boundary deriv " << m_left << " = "; + ss << m_left_value << ", right boundary deriv " << m_right << " = "; + ss << m_right_value << std::endl; + if (m_made_monotonic) { + ss << "(spline has been adjusted for piece-wise monotonicity)"; + } + return ss.str(); } -#endif // HAVE_SSTREAM - +#endif // HAVE_SSTREAM -namespace internal -{ +namespace internal { // band_matrix implementation // ------------------------- -band_matrix::band_matrix(int dim, int n_u, int n_l) -{ - resize(dim, n_u, n_l); +band_matrix::band_matrix(int dim, int n_u, int n_l) { resize(dim, n_u, n_l); } +void band_matrix::resize(int dim, int n_u, int n_l) { + assert(dim > 0); + assert(n_u >= 0); + assert(n_l >= 0); + m_upper.resize(n_u + 1); + m_lower.resize(n_l + 1); + for (size_t i = 0; i < m_upper.size(); i++) { + m_upper[i].resize(dim); + } + for (size_t i = 0; i < m_lower.size(); i++) { + m_lower[i].resize(dim); + } } -void band_matrix::resize(int dim, int n_u, int n_l) -{ - assert(dim>0); - assert(n_u>=0); - assert(n_l>=0); - m_upper.resize(n_u+1); - m_lower.resize(n_l+1); - for(size_t i=0; i0) { - return m_upper[0].size(); - } else { - return 0; - } +int band_matrix::dim() const { + if (m_upper.size() > 0) { + return m_upper[0].size(); + } else { + return 0; + } } - // defines the new operator (), so that we can access the elements // by A(i,j), index going from i=0,...,dim()-1 -double & band_matrix::operator () (int i, int j) -{ - int k=j-i; // what band is the entry - assert( (i>=0) && (i=0) && (j diagonal, k<0 lower left part, k>0 upper right part - if(k>=0) return m_upper[k][i]; - else return m_lower[-k][i]; +double& band_matrix::operator()(int i, int j) { + int k = j - i; // what band is the entry + assert((i >= 0) && (i < dim()) && (j >= 0) && (j < dim())); + assert((-num_lower() <= k) && (k <= num_upper())); + // k=0 -> diagonal, k<0 lower left part, k>0 upper right part + if (k >= 0) + return m_upper[k][i]; + else + return m_lower[-k][i]; } -double band_matrix::operator () (int i, int j) const -{ - int k=j-i; // what band is the entry - assert( (i>=0) && (i=0) && (j diagonal, k<0 lower left part, k>0 upper right part - if(k>=0) return m_upper[k][i]; - else return m_lower[-k][i]; +double band_matrix::operator()(int i, int j) const { + int k = j - i; // what band is the entry + assert((i >= 0) && (i < dim()) && (j >= 0) && (j < dim())); + assert((-num_lower() <= k) && (k <= num_upper())); + // k=0 -> diagonal, k<0 lower left part, k>0 upper right part + if (k >= 0) + return m_upper[k][i]; + else + return m_lower[-k][i]; } // second diag (used in LU decomposition), saved in m_lower -double band_matrix::saved_diag(int i) const -{ - assert( (i>=0) && (i= 0) && (i < dim())); + return m_lower[0][i]; } -double & band_matrix::saved_diag(int i) -{ - assert( (i>=0) && (i= 0) && (i < dim())); + return m_lower[0][i]; } // LR-Decomposition of a band matrix -void band_matrix::lu_decompose() -{ - int i_max,j_max; - int j_min; - double x; - - // preconditioning - // normalize column i so that a_ii=1 - for(int i=0; idim(); i++) { - assert(this->operator()(i,i)!=0.0); - this->saved_diag(i)=1.0/this->operator()(i,i); - j_min=std::max(0,i-this->num_lower()); - j_max=std::min(this->dim()-1,i+this->num_upper()); - for(int j=j_min; j<=j_max; j++) { - this->operator()(i,j) *= this->saved_diag(i); - } - this->operator()(i,i)=1.0; // prevents rounding errors +void band_matrix::lu_decompose() { + int i_max, j_max; + int j_min; + double x; + + // preconditioning + // normalize column i so that a_ii=1 + for (int i = 0; i < this->dim(); i++) { + assert(this->operator()(i, i) != 0.0); + this->saved_diag(i) = 1.0 / this->operator()(i, i); + j_min = std::max(0, i - this->num_lower()); + j_max = std::min(this->dim() - 1, i + this->num_upper()); + for (int j = j_min; j <= j_max; j++) { + this->operator()(i, j) *= this->saved_diag(i); } - - // Gauss LR-Decomposition - for(int k=0; kdim(); k++) { - i_max=std::min(this->dim()-1,k+this->num_lower()); // num_lower not a mistake! - for(int i=k+1; i<=i_max; i++) { - assert(this->operator()(k,k)!=0.0); - x=-this->operator()(i,k)/this->operator()(k,k); - this->operator()(i,k)=-x; // assembly part of L - j_max=std::min(this->dim()-1,k+this->num_upper()); - for(int j=k+1; j<=j_max; j++) { - // assembly part of R - this->operator()(i,j)=this->operator()(i,j)+x*this->operator()(k,j); - } - } + this->operator()(i, i) = 1.0; // prevents rounding errors + } + + // Gauss LR-Decomposition + for (int k = 0; k < this->dim(); k++) { + i_max = std::min(this->dim() - 1, + k + this->num_lower()); // num_lower not a mistake! + for (int i = k + 1; i <= i_max; i++) { + assert(this->operator()(k, k) != 0.0); + x = -this->operator()(i, k) / this->operator()(k, k); + this->operator()(i, k) = -x; // assembly part of L + j_max = std::min(this->dim() - 1, k + this->num_upper()); + for (int j = k + 1; j <= j_max; j++) { + // assembly part of R + this->operator()(i, j) = + this->operator()(i, j) + x * this->operator()(k, j); + } } + } } // solves Ly=b -std::vector band_matrix::l_solve(const std::vector& b) const -{ - assert( this->dim()==(int)b.size() ); - std::vector x(this->dim()); - int j_start; - double sum; - for(int i=0; idim(); i++) { - sum=0; - j_start=std::max(0,i-this->num_lower()); - for(int j=j_start; joperator()(i,j)*x[j]; - x[i]=(b[i]*this->saved_diag(i)) - sum; - } - return x; +std::vector band_matrix::l_solve(const std::vector& b) const { + assert(this->dim() == (int)b.size()); + std::vector x(this->dim()); + int j_start; + double sum; + for (int i = 0; i < this->dim(); i++) { + sum = 0; + j_start = std::max(0, i - this->num_lower()); + for (int j = j_start; j < i; j++) sum += this->operator()(i, j) * x[j]; + x[i] = (b[i] * this->saved_diag(i)) - sum; + } + return x; } // solves Rx=y -std::vector band_matrix::r_solve(const std::vector& b) const -{ - assert( this->dim()==(int)b.size() ); - std::vector x(this->dim()); - int j_stop; - double sum; - for(int i=this->dim()-1; i>=0; i--) { - sum=0; - j_stop=std::min(this->dim()-1,i+this->num_upper()); - for(int j=i+1; j<=j_stop; j++) sum += this->operator()(i,j)*x[j]; - x[i]=( b[i] - sum ) / this->operator()(i,i); - } - return x; +std::vector band_matrix::r_solve(const std::vector& b) const { + assert(this->dim() == (int)b.size()); + std::vector x(this->dim()); + int j_stop; + double sum; + for (int i = this->dim() - 1; i >= 0; i--) { + sum = 0; + j_stop = std::min(this->dim() - 1, i + this->num_upper()); + for (int j = i + 1; j <= j_stop; j++) sum += this->operator()(i, j) * x[j]; + x[i] = (b[i] - sum) / this->operator()(i, i); + } + return x; } std::vector band_matrix::lu_solve(const std::vector& b, - bool is_lu_decomposed) -{ - assert( this->dim()==(int)b.size() ); - std::vector x,y; - if(is_lu_decomposed==false) { - this->lu_decompose(); - } - y=this->l_solve(b); - x=this->r_solve(y); - return x; + bool is_lu_decomposed) { + assert(this->dim() == (int)b.size()); + std::vector x, y; + if (is_lu_decomposed == false) { + this->lu_decompose(); + } + y = this->l_solve(b); + x = this->r_solve(y); + return x; } -} // namespace internal - - -} // namespace tk +} // namespace internal +} // namespace tk -} // namespace +} // namespace #pragma GCC diagnostic pop diff --git a/src/CCCS.cpp b/src/CCCS.cpp index 72dfda11..68052524 100644 --- a/src/CCCS.cpp +++ b/src/CCCS.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/CCCS.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -22,15 +23,14 @@ using namespace JoSIM; ⎣ 0 0 1 -1 0⎦ ⎣Io ⎦ ⎣ 0⎦ */ -CCCS::CCCS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi) { +CCCS::CCCS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi) { // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -50,80 +50,80 @@ CCCS::CCCS( set_matrix_info(); } -void CCCS::set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc) { +void CCCS::set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc) { // Set the node indices for the controlling nodes and add column indices switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - indexInfo.posIndex_ = nm.at(t.at(0)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GNDNEG: - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::POSNEG: - indexInfo.posIndex_ = nm.at(t.at(0)); - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + indexInfo.posIndex_ = nm.at(t.at(0)); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GNDNEG: + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::POSNEG: + indexInfo.posIndex_ = nm.at(t.at(0)); + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GND: + break; } // Set the node indices for the controlled nodes and add column index info switch (nodeConfig2_) { - case NodeConfig::POSGND: - posIndex2_ = nm.at(t.at(2)); - nc.at(nm.at(t.at(2))).emplace_back( - std::make_pair((1 / netlistInfo.value_), - indexInfo.currentIndex_.value())); - break; - case NodeConfig::GNDNEG: - negIndex2_ = nm.at(t.at(3)); - nc.at(nm.at(t.at(3))).emplace_back( - std::make_pair(-(1 / netlistInfo.value_), - indexInfo.currentIndex_.value())); - break; - case NodeConfig::POSNEG: - posIndex2_ = nm.at(t.at(2)); - negIndex2_ = nm.at(t.at(3)); - nc.at(nm.at(t.at(2))).emplace_back( - std::make_pair((1 / netlistInfo.value_), - indexInfo.currentIndex_.value())); - nc.at(nm.at(t.at(3))).emplace_back( - std::make_pair(-(1 / netlistInfo.value_), - indexInfo.currentIndex_.value())); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + posIndex2_ = nm.at(t.at(2)); + nc.at(nm.at(t.at(2))) + .emplace_back(std::make_pair((1 / netlistInfo.value_), + indexInfo.currentIndex_.value())); + break; + case NodeConfig::GNDNEG: + negIndex2_ = nm.at(t.at(3)); + nc.at(nm.at(t.at(3))) + .emplace_back(std::make_pair(-(1 / netlistInfo.value_), + indexInfo.currentIndex_.value())); + break; + case NodeConfig::POSNEG: + posIndex2_ = nm.at(t.at(2)); + negIndex2_ = nm.at(t.at(3)); + nc.at(nm.at(t.at(2))) + .emplace_back(std::make_pair((1 / netlistInfo.value_), + indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(3))) + .emplace_back(std::make_pair(-(1 / netlistInfo.value_), + indexInfo.currentIndex_.value())); + break; + case NodeConfig::GND: + break; } } void CCCS::set_matrix_info() { switch (nodeConfig2_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(1); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(1); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(1); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(1); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GND: + break; } } \ No newline at end of file diff --git a/src/CCVS.cpp b/src/CCVS.cpp index de18a4df..764c32a9 100644 --- a/src/CCVS.cpp +++ b/src/CCVS.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/CCVS.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -33,16 +34,16 @@ using namespace JoSIM; ⎣ 0 0 1 -1 0 0⎦ ⎣Io ⎦ ⎣ 0⎦ */ -CCVS::CCVS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi, const AnalysisType& at, const double& h) { +CCVS::CCVS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi, const AnalysisType& at, + const double& h) { at_ = at; // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -64,104 +65,104 @@ CCVS::CCVS( set_matrix_info(at, h); } -void CCVS::set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc) { +void CCVS::set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc) { // Set the output node indices and column indices switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - indexInfo.posIndex_ = nm.at(t.at(0)); - nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(-1, currentIndex2_)); - break; - case NodeConfig::GNDNEG: - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(1, currentIndex2_)); - break; - case NodeConfig::POSNEG: - indexInfo.posIndex_ = nm.at(t.at(0)); - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(-1, currentIndex2_)); - nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(1, currentIndex2_)); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + indexInfo.posIndex_ = nm.at(t.at(0)); + nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(-1, currentIndex2_)); + break; + case NodeConfig::GNDNEG: + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(1, currentIndex2_)); + break; + case NodeConfig::POSNEG: + indexInfo.posIndex_ = nm.at(t.at(0)); + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(-1, currentIndex2_)); + nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(1, currentIndex2_)); + break; + case NodeConfig::GND: + break; } // Set the controlling node indices and column indices switch (nodeConfig2_) { - case NodeConfig::POSGND: - posIndex2_ = nm.at(t.at(2)); - nc.at(nm.at(t.at(2))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GNDNEG: - negIndex2_ = nm.at(t.at(3)); - nc.at(nm.at(t.at(3))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::POSNEG: - posIndex2_ = nm.at(t.at(2)); - negIndex2_ = nm.at(t.at(3)); - nc.at(nm.at(t.at(2))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - nc.at(nm.at(t.at(3))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + posIndex2_ = nm.at(t.at(2)); + nc.at(nm.at(t.at(2))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GNDNEG: + negIndex2_ = nm.at(t.at(3)); + nc.at(nm.at(t.at(3))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::POSNEG: + posIndex2_ = nm.at(t.at(2)); + negIndex2_ = nm.at(t.at(3)); + nc.at(nm.at(t.at(2))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(3))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GND: + break; } } void CCVS::set_matrix_info(const AnalysisType& at, const double& h) { switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); - matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); - matrixInfo.rowPointer_.emplace_back(3); - break; - case NodeConfig::GND: - matrixInfo.rowPointer_.emplace_back(1); - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); + matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); + matrixInfo.rowPointer_.emplace_back(3); + break; + case NodeConfig::GND: + matrixInfo.rowPointer_.emplace_back(1); + break; } if (at == AnalysisType::Voltage) { matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); } else if (at == AnalysisType::Phase) { pn2_ = 0; matrixInfo.nonZeros_.emplace_back( - -netlistInfo.value_ * (1.0 / Constants::SIGMA) * ((2 * h) / 3.0)); + -netlistInfo.value_ * (1.0 / Constants::SIGMA) * ((2 * h) / 3.0)); hDepPos_ = matrixInfo.nonZeros_.size() - 1; } matrixInfo.columnIndex_.emplace_back(indexInfo.currentIndex_.value()); switch (nodeConfig2_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(1); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(1); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(1); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(1); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GND: + break; } } @@ -169,6 +170,6 @@ void CCVS::set_matrix_info(const AnalysisType& at, const double& h) { void CCVS::update_timestep(const double& factor) { if (at_ == AnalysisType::Phase) { matrixInfo.nonZeros_.at(hDepPos_) = - factor * matrixInfo.nonZeros_.at(hDepPos_); + factor * matrixInfo.nonZeros_.at(hDepPos_); } } \ No newline at end of file diff --git a/src/Capacitor.cpp b/src/Capacitor.cpp index 12c95454..5457bab4 100644 --- a/src/Capacitor.cpp +++ b/src/Capacitor.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Capacitor.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -28,22 +29,22 @@ using namespace JoSIM; RHS = (8/3)φn-1 - (22/9)φn-2 + (8/9)φn-3 - (1/9)φn-4 */ -Capacitor::Capacitor( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, nodeconnections& nc, - Input& iObj, Spread& spread, int64_t& bi) { +Capacitor::Capacitor(const std::pair& s, + const NodeConfig& ncon, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + Input& iObj, Spread& spread, int64_t& bi) { double spr = 1.0; for (auto i : s.first) { if (i.find("SPREAD=") != std::string::npos) { - spr = - parse_param(i.substr(i.find("SPREAD=") + 7), iObj.parameters, s.second); + spr = parse_param(i.substr(i.find("SPREAD=") + 7), iObj.parameters, + s.second); } } at_ = iObj.argAnal; // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -51,7 +52,7 @@ Capacitor::Capacitor( lm.emplace(s.first.at(0)); // Set the value (Capacitance), this should be the 4th token netlistInfo.value_ = spread.spread_value( - parse_param(s.first.at(3), iObj.parameters, s.second), Spread::CAP, spr); + parse_param(s.first.at(3), iObj.parameters, s.second), Spread::CAP, spr); // Set the node configuration type indexInfo.nodeConfig_ = ncon; // Set current index and increment it @@ -64,12 +65,13 @@ Capacitor::Capacitor( if (at_ == AnalysisType::Voltage) { // If voltage mode analysis then append -(2/3) * (h/C) matrixInfo.nonZeros_.emplace_back( - -(2.0 / 3.0) * (iObj.transSim.tstep() / netlistInfo.value_)); + -(2.0 / 3.0) * (iObj.transSim.tstep() / netlistInfo.value_)); } else if (at_ == AnalysisType::Phase) { // If phase mdoe analysis then append -(4/9) * ((h*h)/C) * (1/σ) matrixInfo.nonZeros_.emplace_back( - -(4.0 / 9.0) * ((iObj.transSim.tstep() * iObj.transSim.tstep()) / - netlistInfo.value_) * (1 / Constants::SIGMA)); + -(4.0 / 9.0) * + ((iObj.transSim.tstep() * iObj.transSim.tstep()) / netlistInfo.value_) * + (1 / Constants::SIGMA)); } } @@ -78,7 +80,6 @@ void Capacitor::update_timestep(const double& factor) { if (at_ == AnalysisType::Voltage) { matrixInfo.nonZeros_.back() = factor * matrixInfo.nonZeros_.back(); } else if (at_ == AnalysisType::Phase) { - matrixInfo.nonZeros_.back() = - factor * factor * matrixInfo.nonZeros_.back(); + matrixInfo.nonZeros_.back() = factor * factor * matrixInfo.nonZeros_.back(); } } \ No newline at end of file diff --git a/src/CliOptions.cpp b/src/CliOptions.cpp index 03b339b4..b28a708f 100644 --- a/src/CliOptions.cpp +++ b/src/CliOptions.cpp @@ -2,15 +2,16 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/CliOptions.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/TypeDefines.hpp" -#include -#include #include -#include #include +#include +#include +#include + +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/TypeDefines.hpp" using namespace JoSIM; @@ -32,7 +33,7 @@ tokens_t CliOptions::argv_to_tokens(const int64_t& argc, const char** argv) { } vector_pair_t CliOptions::argument_pairs( - const tokens_t& tokens) { + const tokens_t& tokens) { // Variable to store the argument pairs vector_pair_t ap; // Loop through the argument tokens @@ -46,8 +47,9 @@ vector_pair_t CliOptions::argument_pairs( // If the string is a switch, remove the -- if (tempT.at(0).at(0) == '-') { // Remove all '-' chars, indicating a switch. - tempT.at(0).erase(std::remove( - tempT.at(0).begin(), tempT.at(0).end(), '-'), tempT.at(0).end()); + tempT.at(0).erase( + std::remove(tempT.at(0).begin(), tempT.at(0).end(), '-'), + tempT.at(0).end()); // Store the switch identifying char 'a' for "analysis" ap.emplace_back(std::make_pair(tempT.at(0).at(0), std::nullopt)); } else { @@ -88,7 +90,7 @@ CliOptions CliOptions::parse(int64_t argc, const char** argv) { CliOptions out; // Parse and generate argument pairs from tokens vector_pair_t ap = - out.argument_pairs(out.argv_to_tokens(argc, argv)); + out.argument_pairs(out.argv_to_tokens(argc, argv)); // Loop through the argument pairs for (auto i : ap) { // If the argument is not accompanied by any switch @@ -100,84 +102,83 @@ CliOptions CliOptions::parse(int64_t argc, const char** argv) { } else { // Use the char in a case statment switch (i.first.value()) { - // Set analysis type - case 'a': - if (!i.second) { - Errors::cli_errors(CLIErrors::NO_ANALYSIS); - } else if (i.second.value() == "0") { - out.analysis_type = AnalysisType::Voltage; - } else if (i.second.value() == "1") { - out.analysis_type = AnalysisType::Phase; - } else { - Errors::cli_errors(CLIErrors::INVALID_ANALYSIS); - } - break; - // Show help menu - case 'h': - display_help(); - exit(0); - // Set input to standard input - case 'i': - out.cir_file_name = std::nullopt; - break; - // Enable minimal reporting - case 'm': - try { - out.minimal = std::stoi(i.second.value_or("1")); - } catch (const std::invalid_argument& ia) { - Errors::cli_errors( - CLIErrors::INVALID_MINIMAL, i.second.value()); - } - break; - // Set output file - case 'o': - // If no file name is specified but output is specified - if (!i.second) { - // Store the output in a file called output.csv at cwd - out.output_file = OutputFile( - std::filesystem::current_path().append("output.csv").string()); - // If a file name was given - } else { - out.output_file = OutputFile(i.second.value()); - } - break; - // Enable parallel processing (EXPERIMENTAL) - case 'p': + // Set analysis type + case 'a': + if (!i.second) { + Errors::cli_errors(CLIErrors::NO_ANALYSIS); + } else if (i.second.value() == "0") { + out.analysis_type = AnalysisType::Voltage; + } else if (i.second.value() == "1") { + out.analysis_type = AnalysisType::Phase; + } else { + Errors::cli_errors(CLIErrors::INVALID_ANALYSIS); + } + break; + // Show help menu + case 'h': + display_help(); + exit(0); + // Set input to standard input + case 'i': + out.cir_file_name = std::nullopt; + break; + // Enable minimal reporting + case 'm': + try { + out.minimal = std::stoi(i.second.value_or("1")); + } catch (const std::invalid_argument& ia) { + Errors::cli_errors(CLIErrors::INVALID_MINIMAL, i.second.value()); + } + break; + // Set output file + case 'o': + // If no file name is specified but output is specified + if (!i.second) { + // Store the output in a file called output.csv at cwd + out.output_file = OutputFile( + std::filesystem::current_path().append("output.csv").string()); + // If a file name was given + } else { + out.output_file = OutputFile(i.second.value()); + } + break; + // Enable parallel processing (EXPERIMENTAL) + case 'p': #ifdef _OPENMP - std::cout << "Parallelization is ENABLED" << std::endl; + std::cout << "Parallelization is ENABLED" << std::endl; #else - std::cout << "Parallelization is DISABLED" << std::endl; + std::cout << "Parallelization is DISABLED" << std::endl; #endif - break; - // Enable verbose mode - case 'V': - try { - out.verbose = std::stoi(i.second.value_or("1")); - } catch (const std::invalid_argument& ia) { - Errors::verbosity_errors( - VerbosityErrors::INVALID_VERBOSITY_LEVEL, i.second.value()); - } - break; - // Show version info - case 'v': - exit(0); - break; - // Set the solver type between KLU and SLU - case 'x': - if (!i.second) { - Errors::cli_errors(CLIErrors::NO_SOLVER); - } else if (i.second.value() == "0") { - out.SLU = false; - } else if (i.second.value() == "1") { - out.SLU = true; - } else { - Errors::cli_errors(CLIErrors::INVALID_SOLVER); - } - break; - // Unknown switch was specified - default: - Errors::cli_errors( - CLIErrors::UNKNOWN_SWITCH, std::string(1, i.first.value())); + break; + // Enable verbose mode + case 'V': + try { + out.verbose = std::stoi(i.second.value_or("1")); + } catch (const std::invalid_argument& ia) { + Errors::verbosity_errors(VerbosityErrors::INVALID_VERBOSITY_LEVEL, + i.second.value()); + } + break; + // Show version info + case 'v': + exit(0); + break; + // Set the solver type between KLU and SLU + case 'x': + if (!i.second) { + Errors::cli_errors(CLIErrors::NO_SOLVER); + } else if (i.second.value() == "0") { + out.SLU = false; + } else if (i.second.value() == "1") { + out.SLU = true; + } else { + Errors::cli_errors(CLIErrors::INVALID_SOLVER); + } + break; + // Unknown switch was specified + default: + Errors::cli_errors(CLIErrors::UNKNOWN_SWITCH, + std::string(1, i.first.value())); } } } @@ -199,16 +200,14 @@ CliOptions CliOptions::parse(int64_t argc, const char** argv) { if (!out.minimal) { // Print to screen the input and output locations if (out.cir_file_name) { - std::cout << "Input: " << out.cir_file_name.value() - << std::endl; + std::cout << "Input: " << out.cir_file_name.value() << std::endl; } else { - std::cout << "Input: " << "standard input" - << std::endl; + std::cout << "Input: " + << "standard input" << std::endl; } std::cout << std::endl; if (out.output_file) { - std::cout << "Output: " << out.output_file.value().name() - << std::endl; + std::cout << "Output: " << out.output_file.value().name() << std::endl; std::cout << std::endl; } } @@ -224,114 +223,112 @@ void CliOptions::display_help() { // Analysis type // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-a" << std::setw(3) << std::left - << "|" - << "Specifies the analysis type." << std::endl; + << "|" + << "Specifies the analysis type." << std::endl; std::cout << std::setw(16) << std::left << "--analysis=" << std::setw(3) - << std::left << "|" - << "0 for Voltage analysis." << std::endl; + << std::left << "|" + << "0 for Voltage analysis." << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" - << "1 for Phase analysis (Default)." << std::endl; + << "|" + << "1 for Phase analysis (Default)." << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Help menu // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-h" << std::setw(3) << std::left - << "|" - << "Displays this help menu" << std::endl; + << "|" + << "Displays this help menu" << std::endl; std::cout << std::setw(16) << std::left << "--help" << std::setw(3) - << std::left << "|" - << " " << std::endl; + << std::left << "|" + << " " << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Input from standard in // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-i" << std::setw(3) << std::left - << "|" - << "Input circuit netlist from standard input." - << std::endl; + << "|" + << "Input circuit netlist from standard input." << std::endl; std::cout << std::setw(16) << std::left << "--input" << std::setw(3) - << std::left << "|" - << "This command ignores any additional input file specified." - << std::endl; - std::cout - << std::setw(16) << std::left << " " << std::setw(3) << std::left << "|" - << "Reads from standard input until the " << - ".end command or EOF character is specified." - << std::endl; + << std::left << "|" + << "This command ignores any additional input file specified." + << std::endl; + std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left + << "|" + << "Reads from standard input until the " + << ".end command or EOF character is specified." << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Minimal output // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-m" << std::setw(3) << std::left - << "|" - << "Disables most output." << std::endl; + << "|" + << "Disables most output." << std::endl; std::cout << std::setw(16) << std::left << "--minimal" << std::setw(3) - << std::left << "|" - << " " << std::endl; + << std::left << "|" + << " " << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Output // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-o" << std::setw(3) << std::left - << "|" - << "Specify output file for simulation results (.csv)." - << std::endl; + << "|" + << "Specify output file for simulation results (.csv)." + << std::endl; std::cout << std::setw(16) << std::left << "--output=" << std::setw(3) - << std::left << "|" - << "Default will be output.csv if no file is specified." - << std::endl; + << std::left << "|" + << "Default will be output.csv if no file is specified." + << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Parallel Processing // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-p" << std::setw(3) << std::left - << "|" - << "(EXPERIMENTAL) Enables parallelization of certain functions." - << std::endl; + << "|" + << "(EXPERIMENTAL) Enables parallelization of certain functions." + << std::endl; std::cout << std::setw(16) << std::left << "--parallel" << std::setw(3) - << std::left << "|" - << "Requires compilation with OPENMP switch enabled." << std::endl; + << std::left << "|" + << "Requires compilation with OPENMP switch enabled." << std::endl; std::cout - << std::setw(16) << std::left << " " << std::setw(3) << std::left << "|" - << "Threshold applies, overhead on small circuits negates performance." - << std::endl; + << std::setw(16) << std::left << " " << std::setw(3) << std::left << "|" + << "Threshold applies, overhead on small circuits negates performance." + << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Verbose switch // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-V" << std::setw(3) << std::left - << "|" - << "Runs JoSIM in verbose mode." << std::endl; + << "|" + << "Runs JoSIM in verbose mode." << std::endl; std::cout << std::setw(16) << std::left << "--Verbose=" << std::setw(3) - << std::left << "|" - << "Defaults to minimal(1), can be medium(2) or maximum(3)" - << std::endl; + << std::left << "|" + << "Defaults to minimal(1), can be medium(2) or maximum(3)" + << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Version info // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-v" << std::setw(3) << std::left - << "|" - << "Displays the JoSIM version info only." << std::endl; + << "|" + << "Displays the JoSIM version info only." << std::endl; std::cout << std::setw(16) << std::left << "--version" << std::setw(3) - << std::left << "|" - << " " << std::endl; + << std::left << "|" + << " " << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // Solver type // --------------------------------------------------------------------------- std::cout << std::setw(16) << std::left << "-x" << std::setw(3) << std::left - << "|" - << "Specifies the analysis type." << std::endl; + << "|" + << "Specifies the analysis type." << std::endl; std::cout << std::setw(16) << std::left << "--xsolver=" << std::setw(3) - << std::left << "|" - << "0 for KLU analysis. (Default)" << std::endl; + << std::left << "|" + << "0 for KLU analysis. (Default)" << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" - << "1 for SuperLU analysis." << std::endl; + << "|" + << "1 for SuperLU analysis." << std::endl; std::cout << std::setw(16) << std::left << " " << std::setw(3) << std::left - << "|" << std::endl; + << "|" << std::endl; // --------------------------------------------------------------------------- std::cout << std::endl; @@ -343,13 +340,12 @@ void CliOptions::display_help() { void CliOptions::version_info() { std::cout << std::endl; std::cout - << "JoSIM: Josephson Junction Superconductive SPICE Circuit Simulator" - << std::endl; + << "JoSIM: Josephson Junction Superconductive SPICE Circuit Simulator" + << std::endl; std::cout << "Copyright (C) 2020 by Johannes Delport (jdelport@sun.ac.za)" - << std::endl; + << std::endl; std::cout << "v" << VERSION << "." << GIT_COMMIT_HASH << " compiled on " - << __DATE__ << " at " - << __TIME__ << std::endl; + << __DATE__ << " at " << __TIME__ << std::endl; #ifndef NDEBUG std::cout << "(Debug)" << std::endl; #endif diff --git a/src/CurrentSource.cpp b/src/CurrentSource.cpp index b2710f01..706e4de9 100644 --- a/src/CurrentSource.cpp +++ b/src/CurrentSource.cpp @@ -2,8 +2,9 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/CurrentSource.hpp" -#include "JoSIM/Misc.hpp" + #include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" using namespace JoSIM; @@ -14,13 +15,14 @@ using namespace JoSIM; ⎣ 0 0⎦ ⎣ V⁻⎦ ⎣ -Io⎦ */ -CurrentSource::CurrentSource( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, const int64_t& si) { +CurrentSource::CurrentSource(const std::pair& s, + const NodeConfig& ncon, const nodemap& nm, + std::unordered_set& lm, + const int64_t& si) { // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -36,17 +38,17 @@ CurrentSource::CurrentSource( void CurrentSource::set_node_indices(const tokens_t& t, const nodemap& nm) { switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - indexInfo.posIndex_ = nm.at(t.at(0)); - break; - case NodeConfig::GNDNEG: - indexInfo.negIndex_ = nm.at(t.at(1)); - break; - case NodeConfig::POSNEG: - indexInfo.posIndex_ = nm.at(t.at(0)); - indexInfo.negIndex_ = nm.at(t.at(1)); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + indexInfo.posIndex_ = nm.at(t.at(0)); + break; + case NodeConfig::GNDNEG: + indexInfo.negIndex_ = nm.at(t.at(1)); + break; + case NodeConfig::POSNEG: + indexInfo.posIndex_ = nm.at(t.at(0)); + indexInfo.negIndex_ = nm.at(t.at(1)); + break; + case NodeConfig::GND: + break; } } diff --git a/src/Errors.cpp b/src/Errors.cpp index ce6de215..71596c3c 100644 --- a/src/Errors.cpp +++ b/src/Errors.cpp @@ -10,847 +10,849 @@ using namespace JoSIM; void Errors::cli_errors(CLIErrors errorCode, string_o message) { std::string formattedMessage = "Command Line Interface\n"; switch (errorCode) { - case CLIErrors::NO_OUTPUT: - formattedMessage += - "No output file name specified. Using default (output.csv).\n"; - formattedMessage += - "This file will be stored in the current working directory."; - warning_message(formattedMessage); - break; - case CLIErrors::NO_INPUT: - formattedMessage += "No input file was specified.\n"; - formattedMessage += "Continuing by reading from standard input."; - warning_message(formattedMessage); - break; - case CLIErrors::UNKNOWN_SWITCH: - formattedMessage += "Unknown option '" + message.value_or("") + - "' specified. Please refer to the help menu."; - warning_message(formattedMessage); - break; - case CLIErrors::UNKNOWN_OUTPUT_TYPE: - formattedMessage += "Unknown output type " + message.value_or("") + - " specified. CSV will be used instead."; - warning_message(formattedMessage); - break; - case CLIErrors::TOO_FEW_ARGUMENTS: - formattedMessage += "Missing input arguments\n"; - formattedMessage += "Usage: josim [options] input_netlist\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - case CLIErrors::INVALID_ANALYSIS: - formattedMessage += - "Invalid analysis type specified. 0 - Voltage, 1 - Phase.\n"; - formattedMessage += "Usage: josim [options] input_netlist\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - case CLIErrors::INVALID_SOLVER: - formattedMessage += - "Invalid solver type specified. 0 - KLU, 1 - SLU.\n"; - formattedMessage += "Usage: josim [options] input_netlist\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - case CLIErrors::INVALID_INTEGRATION: - formattedMessage += - "Invalid integration method specified. 0 - Trapezoidal, 1 - Gear.\n"; - formattedMessage += "Usage: josim [options] input_netlist\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - case CLIErrors::NO_ANALYSIS: - formattedMessage += - "No analysis was specified. Reverting to default (0 - Voltage).\n"; - formattedMessage += - "Please refer to the help menu (-h) or manual for further information."; - warning_message(formattedMessage); - break; - case CLIErrors::NO_SOLVER: - formattedMessage += - "No solver was specified. Reverting to default (0 - KLU).\n"; - formattedMessage += - "Please refer to the help menu (-h) or manual for further information."; - warning_message(formattedMessage); - break; - case CLIErrors::NO_INTEGRATION: - formattedMessage += "No integration method specified\n."; - formattedMessage += "Reverting to default (0 - Trapezoidal).\n"; - formattedMessage += - "Please refer to the help menu (-h) or manual for further information."; - warning_message(formattedMessage); - break; - case CLIErrors::INVALID_CONVENTION: - formattedMessage += - "Invalid subcircuit convention specified. 0 - JSIM, 1 - WRspice.\n"; - formattedMessage += "Usage: josim [options] input_netlist\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - case CLIErrors::INPUT_SAME_OUTPUT: - formattedMessage += "Output file name is the same as input file name.\n"; - formattedMessage += - "This will cause irreversible changes to input file.\n"; - formattedMessage += "Please choose a different output file name."; - throw std::runtime_error(formattedMessage); - case CLIErrors::NO_CONVENTION: - formattedMessage += - "No convention was specified. Reverting to default (0 - JSIM).\n"; - formattedMessage += - "Please refer to the help menu (-h) or manual for further information."; - warning_message(formattedMessage); - break; - case CLIErrors::INVALID_MINIMAL: - formattedMessage += - "Invalid minimal output specified. 0 - Off, 1 - On.\n"; - formattedMessage += "Usage: josim [options] input_netlist\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += "Unknown handling error.\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case CLIErrors::NO_OUTPUT: + formattedMessage += + "No output file name specified. Using default (output.csv).\n"; + formattedMessage += + "This file will be stored in the current working directory."; + warning_message(formattedMessage); + break; + case CLIErrors::NO_INPUT: + formattedMessage += "No input file was specified.\n"; + formattedMessage += "Continuing by reading from standard input."; + warning_message(formattedMessage); + break; + case CLIErrors::UNKNOWN_SWITCH: + formattedMessage += "Unknown option '" + message.value_or("") + + "' specified. Please refer to the help menu."; + warning_message(formattedMessage); + break; + case CLIErrors::UNKNOWN_OUTPUT_TYPE: + formattedMessage += "Unknown output type " + message.value_or("") + + " specified. CSV will be used instead."; + warning_message(formattedMessage); + break; + case CLIErrors::TOO_FEW_ARGUMENTS: + formattedMessage += "Missing input arguments\n"; + formattedMessage += "Usage: josim [options] input_netlist\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + case CLIErrors::INVALID_ANALYSIS: + formattedMessage += + "Invalid analysis type specified. 0 - Voltage, 1 - Phase.\n"; + formattedMessage += "Usage: josim [options] input_netlist\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + case CLIErrors::INVALID_SOLVER: + formattedMessage += "Invalid solver type specified. 0 - KLU, 1 - SLU.\n"; + formattedMessage += "Usage: josim [options] input_netlist\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + case CLIErrors::INVALID_INTEGRATION: + formattedMessage += + "Invalid integration method specified. 0 - Trapezoidal, 1 - Gear.\n"; + formattedMessage += "Usage: josim [options] input_netlist\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + case CLIErrors::NO_ANALYSIS: + formattedMessage += + "No analysis was specified. Reverting to default (0 - Voltage).\n"; + formattedMessage += + "Please refer to the help menu (-h) or manual for further " + "information."; + warning_message(formattedMessage); + break; + case CLIErrors::NO_SOLVER: + formattedMessage += + "No solver was specified. Reverting to default (0 - KLU).\n"; + formattedMessage += + "Please refer to the help menu (-h) or manual for further " + "information."; + warning_message(formattedMessage); + break; + case CLIErrors::NO_INTEGRATION: + formattedMessage += "No integration method specified\n."; + formattedMessage += "Reverting to default (0 - Trapezoidal).\n"; + formattedMessage += + "Please refer to the help menu (-h) or manual for further " + "information."; + warning_message(formattedMessage); + break; + case CLIErrors::INVALID_CONVENTION: + formattedMessage += + "Invalid subcircuit convention specified. 0 - JSIM, 1 - WRspice.\n"; + formattedMessage += "Usage: josim [options] input_netlist\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + case CLIErrors::INPUT_SAME_OUTPUT: + formattedMessage += "Output file name is the same as input file name.\n"; + formattedMessage += + "This will cause irreversible changes to input file.\n"; + formattedMessage += "Please choose a different output file name."; + throw std::runtime_error(formattedMessage); + case CLIErrors::NO_CONVENTION: + formattedMessage += + "No convention was specified. Reverting to default (0 - JSIM).\n"; + formattedMessage += + "Please refer to the help menu (-h) or manual for further " + "information."; + warning_message(formattedMessage); + break; + case CLIErrors::INVALID_MINIMAL: + formattedMessage += + "Invalid minimal output specified. 0 - Off, 1 - On.\n"; + formattedMessage += "Usage: josim [options] input_netlist\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += "Unknown handling error.\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } void Errors::input_errors(InputErrors errorCode, string_o message) { std::string formattedMessage = "Input\n"; switch (errorCode) { - case InputErrors::CANNOT_OPEN_FILE: - formattedMessage += - "Input file " + message.value_or("") + " cannot be found or opened.\n"; - formattedMessage += - "Please ensure that the file exists and can be opened.\n\n"; - formattedMessage += "For further help use the -h switch"; - throw std::runtime_error(formattedMessage); - case InputErrors::CYCLIC_INCLUDE: - formattedMessage += - "Attempting to include file " + message.value_or("") + ".\n"; - formattedMessage += "This is the same file as input file.\n\n"; - formattedMessage += "Preventing cyclic includes."; - throw std::runtime_error(formattedMessage); - case InputErrors::MISSING_SUBCKT_IO: - formattedMessage += "Missing subcircuit io.\n"; - formattedMessage += "Please recheck the netlist and try again."; - throw std::runtime_error(formattedMessage); - case InputErrors::MISSING_SUBCKT_NAME: - formattedMessage += "Missing subcircuit name.\n"; - formattedMessage += "Please recheck the netlist and try again."; - throw std::runtime_error(formattedMessage); - case InputErrors::SUBCKT_CONTROLS: - formattedMessage += - "Subcircuit " + message.value_or("") + " contains controls.\n"; - formattedMessage += "Controls are reserved for the main design.\n"; - formattedMessage += "These controls will be ignored."; - warning_message(formattedMessage); - break; - case InputErrors::MISSING_MAIN: - formattedMessage += "Missing main design in netlist.\n"; - formattedMessage += - "This design will not simulate without a main design."; - throw std::runtime_error(formattedMessage); - case InputErrors::UNKNOWN_SUBCKT: - formattedMessage += - "The subcircuit in the following line was not found:\n"; - formattedMessage += message.value() + "\n"; - formattedMessage += - "Please ensure all subcircuits exist and are correctly named."; - throw std::runtime_error(formattedMessage); - case InputErrors::EMPTY_FILE: - formattedMessage += - "The file \"" + message.value_or("") + "\" contains no lines.\n"; - formattedMessage += - "Please check the input file and ensure that the file is not empty."; - throw std::runtime_error(formattedMessage); - case InputErrors::IO_MISMATCH: - formattedMessage += - "The IO of line \"" + message.value_or("") + "\" does not " - "match the subcircuit IO.\n"; - formattedMessage += - "Please check the line and ensure correct IO and " - "that parameters do not contain spaces."; - throw std::runtime_error(formattedMessage); - case InputErrors::UNKNOWN_CONTROL: - formattedMessage += - "The control \"" + message.value_or("") + "\" is not known.\n"; - formattedMessage += - "Please consult the syntax guide for a list of available controls."; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += "Unknown input error.\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case InputErrors::CANNOT_OPEN_FILE: + formattedMessage += "Input file " + message.value_or("") + + " cannot be found or opened.\n"; + formattedMessage += + "Please ensure that the file exists and can be opened.\n\n"; + formattedMessage += "For further help use the -h switch"; + throw std::runtime_error(formattedMessage); + case InputErrors::CYCLIC_INCLUDE: + formattedMessage += + "Attempting to include file " + message.value_or("") + ".\n"; + formattedMessage += "This is the same file as input file.\n\n"; + formattedMessage += "Preventing cyclic includes."; + throw std::runtime_error(formattedMessage); + case InputErrors::MISSING_SUBCKT_IO: + formattedMessage += "Missing subcircuit io.\n"; + formattedMessage += "Please recheck the netlist and try again."; + throw std::runtime_error(formattedMessage); + case InputErrors::MISSING_SUBCKT_NAME: + formattedMessage += "Missing subcircuit name.\n"; + formattedMessage += "Please recheck the netlist and try again."; + throw std::runtime_error(formattedMessage); + case InputErrors::SUBCKT_CONTROLS: + formattedMessage += + "Subcircuit " + message.value_or("") + " contains controls.\n"; + formattedMessage += "Controls are reserved for the main design.\n"; + formattedMessage += "These controls will be ignored."; + warning_message(formattedMessage); + break; + case InputErrors::MISSING_MAIN: + formattedMessage += "Missing main design in netlist.\n"; + formattedMessage += + "This design will not simulate without a main design."; + throw std::runtime_error(formattedMessage); + case InputErrors::UNKNOWN_SUBCKT: + formattedMessage += + "The subcircuit in the following line was not found:\n"; + formattedMessage += message.value() + "\n"; + formattedMessage += + "Please ensure all subcircuits exist and are correctly named."; + throw std::runtime_error(formattedMessage); + case InputErrors::EMPTY_FILE: + formattedMessage += + "The file \"" + message.value_or("") + "\" contains no lines.\n"; + formattedMessage += + "Please check the input file and ensure that the file is not empty."; + throw std::runtime_error(formattedMessage); + case InputErrors::IO_MISMATCH: + formattedMessage += "The IO of line \"" + message.value_or("") + + "\" does not " + "match the subcircuit IO.\n"; + formattedMessage += + "Please check the line and ensure correct IO and " + "that parameters do not contain spaces."; + throw std::runtime_error(formattedMessage); + case InputErrors::UNKNOWN_CONTROL: + formattedMessage += + "The control \"" + message.value_or("") + "\" is not known.\n"; + formattedMessage += + "Please consult the syntax guide for a list of available controls."; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += "Unknown input error.\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } void Errors::invalid_component_errors(ComponentErrors errorCode, - string_o message) { + string_o message) { std::string formattedMessage = "Components\n"; switch (errorCode) { - case ComponentErrors::INVALID_COMPONENT_DECLARATION: - formattedMessage += "Invalid component declaration detected.\n"; - formattedMessage += "Infringing line: " + message.value_or("") + "\n"; - formattedMessage += - "Please refer to the documentation for the correct notation."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::BOTH_GROUND: - formattedMessage += - "Both nodes are grounded for the following component.\n"; - formattedMessage += "Component: " + message.value_or(""); - warning_message(formattedMessage); - break; - case ComponentErrors::GROUNDED_VOLTAGE_SOURCE: - formattedMessage += "Both nodes are grounded for the following source.\n"; - formattedMessage += "Component: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::RES_ERROR: - formattedMessage += "Resistor value error\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::CAP_ERROR: - formattedMessage += "Capacitor value error\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::IND_ERROR: - formattedMessage += "Inductor value error\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::LABEL_ERROR: - formattedMessage += "Invalid component label: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::MISSING_LABEL: - formattedMessage += "No component label. This should not happen.\n"; - formattedMessage += "Infringing line: " + message.value_or("") + "\n"; - formattedMessage += - "Please contact the developer as this is possibly a bug."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::MISSING_PNODE: - formattedMessage += "No positive node. This should not happen.\n"; - formattedMessage += "Infringing line: " + message.value_or("") + "\n"; - formattedMessage += - "Please contact the developer as this is possibly a bug."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::MISSING_NNODE: - formattedMessage += "No negative node. This should not happen.\n"; - formattedMessage += "Infringing line: " + message.value_or("") + "\n"; - formattedMessage += - "Please contact the developer as this is possibly a bug."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::MISSING_JJMODEL: - formattedMessage += - "No junction model is specified for junction " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::MODEL_NOT_DEFINED: - formattedMessage += "The specified model is not defined.\n"; - formattedMessage += "Missing model: " + message.value_or("") + "\n"; - formattedMessage += "Using default model as specified in the manual."; - warning_message(formattedMessage); - break; - case ComponentErrors::MODEL_AREA_NOT_GIVEN: - formattedMessage += - "No area specified for junction " + message.value_or("") + "\n"; - formattedMessage += "Using default: AREA=1.0"; - warning_message(formattedMessage); - break; - case ComponentErrors::DUPLICATE_LABEL: - formattedMessage += - "Duplicate label " + message.value_or("") + " detected.\n"; - formattedMessage += - "The program will now terminate. Please recheck the netlist."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::INVALID_SUBCIRCUIT_NODES: - formattedMessage += - "The nodes of " + message.value_or("") + - " do not match the subcicuit nodes.\n"; - formattedMessage += - "Please recheck the nodes required by the subcircuit and try again."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::TIME_ERROR: - formattedMessage += "Time delay value error\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::MISSING_SUBCIRCUIT_NAME: - formattedMessage += - "The subcircuit for " + message.value_or("") + - " was not found in the file.\n"; - formattedMessage += "Please recheck the subcircuit name and try again."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::MUT_ERROR: - formattedMessage += "Invalid mutual coupling definition found.\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::INVALID_EXPR: - formattedMessage += "Invalid expression statement found.\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::INVALID_TX_DEFINED: - formattedMessage += "Invalid definition for transmission line found.\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::INVALID_TX_RESOLUTION: - formattedMessage += - "Time delay for transmission line is less than simulation timestep.\n"; - formattedMessage += - "Please reduce timestep to less than any transmission line delay.\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ComponentErrors::MISSING_INDUCTOR: - formattedMessage += "Invalid mutual coupling defined."; - formattedMessage += "Missing inductor " + message.value_or("") + "\n"; - formattedMessage += - "Please ensure that " + message.value_or("") + " exists."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::UNKNOWN_DEVICE_TYPE: - formattedMessage += "Unkown device type " + message.value_or("") + "\n"; - formattedMessage += - "Please refer to the syntax guide for a list of device types."; - throw std::runtime_error(formattedMessage); - case ComponentErrors::SPECIAL_CHARS: - formattedMessage += - "Label " + message.value_or("") + " contains special characters.\n"; - formattedMessage += - "The use of special characters in label names is not advised.\n"; - formattedMessage += "This might produce unexpected results.\n"; - formattedMessage += "Continuing operation."; - warning_message(formattedMessage); - break; - default: - formattedMessage += "Unknown invalid component error.\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case ComponentErrors::INVALID_COMPONENT_DECLARATION: + formattedMessage += "Invalid component declaration detected.\n"; + formattedMessage += "Infringing line: " + message.value_or("") + "\n"; + formattedMessage += + "Please refer to the documentation for the correct notation."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::BOTH_GROUND: + formattedMessage += + "Both nodes are grounded for the following component.\n"; + formattedMessage += "Component: " + message.value_or(""); + warning_message(formattedMessage); + break; + case ComponentErrors::GROUNDED_VOLTAGE_SOURCE: + formattedMessage += "Both nodes are grounded for the following source.\n"; + formattedMessage += "Component: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::RES_ERROR: + formattedMessage += "Resistor value error\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::CAP_ERROR: + formattedMessage += "Capacitor value error\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::IND_ERROR: + formattedMessage += "Inductor value error\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::LABEL_ERROR: + formattedMessage += "Invalid component label: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::MISSING_LABEL: + formattedMessage += "No component label. This should not happen.\n"; + formattedMessage += "Infringing line: " + message.value_or("") + "\n"; + formattedMessage += + "Please contact the developer as this is possibly a bug."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::MISSING_PNODE: + formattedMessage += "No positive node. This should not happen.\n"; + formattedMessage += "Infringing line: " + message.value_or("") + "\n"; + formattedMessage += + "Please contact the developer as this is possibly a bug."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::MISSING_NNODE: + formattedMessage += "No negative node. This should not happen.\n"; + formattedMessage += "Infringing line: " + message.value_or("") + "\n"; + formattedMessage += + "Please contact the developer as this is possibly a bug."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::MISSING_JJMODEL: + formattedMessage += + "No junction model is specified for junction " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::MODEL_NOT_DEFINED: + formattedMessage += "The specified model is not defined.\n"; + formattedMessage += "Missing model: " + message.value_or("") + "\n"; + formattedMessage += "Using default model as specified in the manual."; + warning_message(formattedMessage); + break; + case ComponentErrors::MODEL_AREA_NOT_GIVEN: + formattedMessage += + "No area specified for junction " + message.value_or("") + "\n"; + formattedMessage += "Using default: AREA=1.0"; + warning_message(formattedMessage); + break; + case ComponentErrors::DUPLICATE_LABEL: + formattedMessage += + "Duplicate label " + message.value_or("") + " detected.\n"; + formattedMessage += + "The program will now terminate. Please recheck the netlist."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::INVALID_SUBCIRCUIT_NODES: + formattedMessage += "The nodes of " + message.value_or("") + + " do not match the subcicuit nodes.\n"; + formattedMessage += + "Please recheck the nodes required by the subcircuit and try again."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::TIME_ERROR: + formattedMessage += "Time delay value error\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::MISSING_SUBCIRCUIT_NAME: + formattedMessage += "The subcircuit for " + message.value_or("") + + " was not found in the file.\n"; + formattedMessage += "Please recheck the subcircuit name and try again."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::MUT_ERROR: + formattedMessage += "Invalid mutual coupling definition found.\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::INVALID_EXPR: + formattedMessage += "Invalid expression statement found.\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::INVALID_TX_DEFINED: + formattedMessage += "Invalid definition for transmission line found.\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::INVALID_TX_RESOLUTION: + formattedMessage += + "Time delay for transmission line is less than simulation " + "timestep.\n"; + formattedMessage += + "Please reduce timestep to less than any transmission line delay.\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ComponentErrors::MISSING_INDUCTOR: + formattedMessage += "Invalid mutual coupling defined."; + formattedMessage += "Missing inductor " + message.value_or("") + "\n"; + formattedMessage += + "Please ensure that " + message.value_or("") + " exists."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::UNKNOWN_DEVICE_TYPE: + formattedMessage += "Unkown device type " + message.value_or("") + "\n"; + formattedMessage += + "Please refer to the syntax guide for a list of device types."; + throw std::runtime_error(formattedMessage); + case ComponentErrors::SPECIAL_CHARS: + formattedMessage += + "Label " + message.value_or("") + " contains special characters.\n"; + formattedMessage += + "The use of special characters in label names is not advised.\n"; + formattedMessage += "This might produce unexpected results.\n"; + formattedMessage += "Continuing operation."; + warning_message(formattedMessage); + break; + default: + formattedMessage += "Unknown invalid component error.\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } void Errors::control_errors(ControlErrors errorCode, string_o message) { std::string formattedMessage = "Controls\n"; switch (errorCode) { - case ControlErrors::TRANS_ERROR: - formattedMessage += - "Invalid transient analysis specified. " + message.value_or("") + "\n"; - formattedMessage += "Substituting default parameters.\n"; - formattedMessage += - "Defaults: TSTEP=1PS TSTOP=1000PS prstart=0PS PRSTEP=1PS"; - warning_message(formattedMessage); - break; - case ControlErrors::PRINT_TOO_MANY_ARGS: - formattedMessage += - "Print request for device current has too many arguments.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "Ignoring the extra argument."; - warning_message(formattedMessage); - break; - case ControlErrors::PRINT_ERROR: - throw std::runtime_error(formattedMessage); - case ControlErrors::PLOT_ERROR: - throw std::runtime_error(formattedMessage); - case ControlErrors::INV_CONTROL: - throw std::runtime_error(formattedMessage); - case ControlErrors::DC_ERROR: - throw std::runtime_error(formattedMessage); - case ControlErrors::AC_ERROR: - throw std::runtime_error(formattedMessage); - case ControlErrors::PHASE_ERROR: - throw std::runtime_error(formattedMessage); - case ControlErrors::NO_SIM: - formattedMessage += - "No simulation type specified. Nothing will be simulated."; - throw std::runtime_error(formattedMessage); - case ControlErrors::UNKNOWN_DEVICE: - formattedMessage += "Unknown device/node " + message.value_or("") + "\n"; - formattedMessage += "Cannot store results for this device/node.\n"; - formattedMessage += "Ignoring this store request."; - warning_message(formattedMessage); - break; - case ControlErrors::CURRENT_THROUGH_VOLT: - formattedMessage += "Requesting current through a voltage source.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This is invalid and the request will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::VOLT_WHEN_PHASE: - formattedMessage += - "Request to store voltage for device " + message.value_or("") + "\n"; - formattedMessage += "Phase mode simulation performed.\n"; - formattedMessage += "Storing device phase instead."; - warning_message(formattedMessage); - break; - case ControlErrors::VOLT_ACROSS_CURRENT: - formattedMessage += "Requesting voltage across a current source.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This is invalid and the request will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::NODEVOLT_WHEN_PHASE: - formattedMessage += - "Request to store nodal voltage for " + message.value_or("") + "\n"; - formattedMessage += "Phase mode simulation performed.\n"; - formattedMessage += "Storing nodal phase instead."; - warning_message(formattedMessage); - break; - case ControlErrors::NODECURRENT: - formattedMessage += - "Request for current of " + message.value_or("") + " is invalid.\n"; - formattedMessage += - "Cannot find device or cannot store current of a node."; - warning_message(formattedMessage); - break; - case ControlErrors::UNKNOWN_NODE: - formattedMessage += - "Node " + message.value_or("") + " was not found in the circuit.\n"; - formattedMessage += "This request for store will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::NODEPHASE_WHEN_VOLT: - formattedMessage += - "Request to store nodal phase for " + message.value_or("") + "\n"; - formattedMessage += "Voltage mode simulation performed.\n"; - formattedMessage += "Storing nodal voltage instead."; - warning_message(formattedMessage); - break; - case ControlErrors::INVALID_NODEV: - formattedMessage += "Invalid node voltage request found.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This request for store will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::INVALID_NODEP: - formattedMessage += "Invalid node phase request found.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This request for store will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::PHASE_WHEN_VOLT: - formattedMessage += "Requesting phase in a voltage simulation.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This request will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::PHASE_OF_VOLT: - formattedMessage += "Requesting phase of a voltage source.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This is invalid and the request will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::PHASE_OF_CURRENT: - formattedMessage += "Requesting phase of a current source.\n"; - formattedMessage += "Line: " + message.value_or("") + "\n"; - formattedMessage += "This is invalid and the request will be ignored."; - warning_message(formattedMessage); - break; - case ControlErrors::INVALID_CURRENT: - formattedMessage += "Invalid request to plot current.\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - warning_message(formattedMessage); - break; - case ControlErrors::MATHOPS: - formattedMessage += - "Mathematical operations on output vectors are not yet supported.\n"; - formattedMessage += "Ignoring plotting of " + message.value_or(""); - warning_message(formattedMessage); - break; - case ControlErrors::UNKNOWN_PLOT: - formattedMessage += "Unknown plot type " + message.value_or("") + "\n"; - formattedMessage += "Ignoring request to plot."; - warning_message(formattedMessage); - break; - case ControlErrors::INVALID_OUTPUT_COMMAND: - formattedMessage += "Invalid request for output found.\n"; - formattedMessage += message.value_or("") + "\n"; - formattedMessage += "Ignoring request and continuing."; - warning_message(formattedMessage); - break; - case ControlErrors::INVALID_FILE_COMMAND: - formattedMessage += "Invalid request for file output found.\n"; - formattedMessage += message.value_or("") + "\n"; - formattedMessage += "Ignoring request and continuing."; - warning_message(formattedMessage); - break; - case ControlErrors::INVALID_IV_COMMAND: - formattedMessage += "Invalid request for IV curve generation found.\n"; - formattedMessage += message.value_or("") + "\n"; - formattedMessage += "Please refer to the manual for proper syntax.\n"; - formattedMessage += "Ignoring request and continuing."; - warning_message(formattedMessage); - break; - case ControlErrors::IV_MODEL_NOT_FOUND: - formattedMessage += "The requested model was not found.\n"; - formattedMessage += message.value_or("") + "\n"; - formattedMessage += "Please ensure the model exists in the netlist.\n"; - error_message(formattedMessage); - default: - formattedMessage += - "Unknown control error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case ControlErrors::TRANS_ERROR: + formattedMessage += "Invalid transient analysis specified. " + + message.value_or("") + "\n"; + formattedMessage += "Substituting default parameters.\n"; + formattedMessage += + "Defaults: TSTEP=1PS TSTOP=1000PS prstart=0PS PRSTEP=1PS"; + warning_message(formattedMessage); + break; + case ControlErrors::PRINT_TOO_MANY_ARGS: + formattedMessage += + "Print request for device current has too many arguments.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "Ignoring the extra argument."; + warning_message(formattedMessage); + break; + case ControlErrors::PRINT_ERROR: + throw std::runtime_error(formattedMessage); + case ControlErrors::PLOT_ERROR: + throw std::runtime_error(formattedMessage); + case ControlErrors::INV_CONTROL: + throw std::runtime_error(formattedMessage); + case ControlErrors::DC_ERROR: + throw std::runtime_error(formattedMessage); + case ControlErrors::AC_ERROR: + throw std::runtime_error(formattedMessage); + case ControlErrors::PHASE_ERROR: + throw std::runtime_error(formattedMessage); + case ControlErrors::NO_SIM: + formattedMessage += + "No simulation type specified. Nothing will be simulated."; + throw std::runtime_error(formattedMessage); + case ControlErrors::UNKNOWN_DEVICE: + formattedMessage += "Unknown device/node " + message.value_or("") + "\n"; + formattedMessage += "Cannot store results for this device/node.\n"; + formattedMessage += "Ignoring this store request."; + warning_message(formattedMessage); + break; + case ControlErrors::CURRENT_THROUGH_VOLT: + formattedMessage += "Requesting current through a voltage source.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This is invalid and the request will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::VOLT_WHEN_PHASE: + formattedMessage += + "Request to store voltage for device " + message.value_or("") + "\n"; + formattedMessage += "Phase mode simulation performed.\n"; + formattedMessage += "Storing device phase instead."; + warning_message(formattedMessage); + break; + case ControlErrors::VOLT_ACROSS_CURRENT: + formattedMessage += "Requesting voltage across a current source.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This is invalid and the request will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::NODEVOLT_WHEN_PHASE: + formattedMessage += + "Request to store nodal voltage for " + message.value_or("") + "\n"; + formattedMessage += "Phase mode simulation performed.\n"; + formattedMessage += "Storing nodal phase instead."; + warning_message(formattedMessage); + break; + case ControlErrors::NODECURRENT: + formattedMessage += + "Request for current of " + message.value_or("") + " is invalid.\n"; + formattedMessage += + "Cannot find device or cannot store current of a node."; + warning_message(formattedMessage); + break; + case ControlErrors::UNKNOWN_NODE: + formattedMessage += + "Node " + message.value_or("") + " was not found in the circuit.\n"; + formattedMessage += "This request for store will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::NODEPHASE_WHEN_VOLT: + formattedMessage += + "Request to store nodal phase for " + message.value_or("") + "\n"; + formattedMessage += "Voltage mode simulation performed.\n"; + formattedMessage += "Storing nodal voltage instead."; + warning_message(formattedMessage); + break; + case ControlErrors::INVALID_NODEV: + formattedMessage += "Invalid node voltage request found.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This request for store will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::INVALID_NODEP: + formattedMessage += "Invalid node phase request found.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This request for store will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::PHASE_WHEN_VOLT: + formattedMessage += "Requesting phase in a voltage simulation.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This request will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::PHASE_OF_VOLT: + formattedMessage += "Requesting phase of a voltage source.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This is invalid and the request will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::PHASE_OF_CURRENT: + formattedMessage += "Requesting phase of a current source.\n"; + formattedMessage += "Line: " + message.value_or("") + "\n"; + formattedMessage += "This is invalid and the request will be ignored."; + warning_message(formattedMessage); + break; + case ControlErrors::INVALID_CURRENT: + formattedMessage += "Invalid request to plot current.\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + warning_message(formattedMessage); + break; + case ControlErrors::MATHOPS: + formattedMessage += + "Mathematical operations on output vectors are not yet supported.\n"; + formattedMessage += "Ignoring plotting of " + message.value_or(""); + warning_message(formattedMessage); + break; + case ControlErrors::UNKNOWN_PLOT: + formattedMessage += "Unknown plot type " + message.value_or("") + "\n"; + formattedMessage += "Ignoring request to plot."; + warning_message(formattedMessage); + break; + case ControlErrors::INVALID_OUTPUT_COMMAND: + formattedMessage += "Invalid request for output found.\n"; + formattedMessage += message.value_or("") + "\n"; + formattedMessage += "Ignoring request and continuing."; + warning_message(formattedMessage); + break; + case ControlErrors::INVALID_FILE_COMMAND: + formattedMessage += "Invalid request for file output found.\n"; + formattedMessage += message.value_or("") + "\n"; + formattedMessage += "Ignoring request and continuing."; + warning_message(formattedMessage); + break; + case ControlErrors::INVALID_IV_COMMAND: + formattedMessage += "Invalid request for IV curve generation found.\n"; + formattedMessage += message.value_or("") + "\n"; + formattedMessage += "Please refer to the manual for proper syntax.\n"; + formattedMessage += "Ignoring request and continuing."; + warning_message(formattedMessage); + break; + case ControlErrors::IV_MODEL_NOT_FOUND: + formattedMessage += "The requested model was not found.\n"; + formattedMessage += message.value_or("") + "\n"; + formattedMessage += "Please ensure the model exists in the netlist.\n"; + error_message(formattedMessage); + default: + formattedMessage += + "Unknown control error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } -void Errors::model_errors(ModelErrors errorCode, - string_o message) { +void Errors::model_errors(ModelErrors errorCode, string_o message) { std::string formattedMessage = "Model\n"; switch (errorCode) { - case ModelErrors::PARAM_TYPE_ERROR: - formattedMessage += "Unknown model parameter specified.\n"; - formattedMessage += "Model line: " + message.value_or("") + "\n"; - formattedMessage += - "Continuing with default model parameters.\n" - "Please consult the syntax guide for more information."; - warning_message(formattedMessage); - break; - case ModelErrors::UNKNOWN_MODEL_TYPE: - formattedMessage += "Unknown model type specified.\n"; - formattedMessage += "Model line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ModelErrors::BAD_MODEL_DEFINITION: - formattedMessage += "Bad model definition found.\n"; - formattedMessage += "Infringing line: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - default: - formattedMessage += "Unknown model error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case ModelErrors::PARAM_TYPE_ERROR: + formattedMessage += "Unknown model parameter specified.\n"; + formattedMessage += "Model line: " + message.value_or("") + "\n"; + formattedMessage += + "Continuing with default model parameters.\n" + "Please consult the syntax guide for more information."; + warning_message(formattedMessage); + break; + case ModelErrors::UNKNOWN_MODEL_TYPE: + formattedMessage += "Unknown model type specified.\n"; + formattedMessage += "Model line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ModelErrors::BAD_MODEL_DEFINITION: + formattedMessage += "Bad model definition found.\n"; + formattedMessage += "Infringing line: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + default: + formattedMessage += "Unknown model error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } -[[noreturn]] void Errors::matrix_errors(MatrixErrors errorCode, string_o message) { +[[noreturn]] void Errors::matrix_errors(MatrixErrors errorCode, + string_o message) { std::string formattedMessage = "Matrix\n"; switch (errorCode) { - case MatrixErrors::NON_SQUARE: - formattedMessage += - "Matrix is not square. Dimensions are " + message.value_or("") + "\n"; - formattedMessage += - "Please contact the developer as this is potentially a bug."; - throw std::runtime_error(formattedMessage); - case MatrixErrors::SANITY_ERROR: - formattedMessage += - "Component " + message.value_or("") + " created a value in the non-zero" - " matrix that is either 0, inf or NaN.\n"; - formattedMessage += - "This is an internal error and the developer should be contacted."; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += - "Unknown matrix error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case MatrixErrors::NON_SQUARE: + formattedMessage += + "Matrix is not square. Dimensions are " + message.value_or("") + "\n"; + formattedMessage += + "Please contact the developer as this is potentially a bug."; + throw std::runtime_error(formattedMessage); + case MatrixErrors::SANITY_ERROR: + formattedMessage += "Component " + message.value_or("") + + " created a value in the non-zero" + " matrix that is either 0, inf or NaN.\n"; + formattedMessage += + "This is an internal error and the developer should be contacted."; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += + "Unknown matrix error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } -[[noreturn]] void Errors::misc_errors(MiscErrors errorCode, - string_o message) { +[[noreturn]] void Errors::misc_errors(MiscErrors errorCode, string_o message) { std::string formattedMessage = "Miscellaneous\n"; switch (errorCode) { - case MiscErrors::STOD_ERROR: - formattedMessage += - "Cannot convert string to double: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - default: - formattedMessage += "Unknown misc error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case MiscErrors::STOD_ERROR: + formattedMessage += + "Cannot convert string to double: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + default: + formattedMessage += "Unknown misc error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } void Errors::function_errors(FunctionErrors errorCode, string_o message) { std::string formattedMessage = "Function\n"; switch (errorCode) { - case FunctionErrors::INITIAL_VALUES: - formattedMessage += "Invalid PWL definition found.\n"; - formattedMessage += - "The value of " + message.value_or("") + " is expected to be 0\n"; - formattedMessage += "Please refer to the PWL definition:\n"; - formattedMessage += "PWL(0 V0 T1 V1 T2 V2 ... Tn Vn)"; - warning_message(formattedMessage); - break; - case FunctionErrors::TOO_FEW_TIMESTEPS: - formattedMessage += - "Total timesteps specified do not match the values specified.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the PWL definition:\n"; - formattedMessage += "PWL(0 0 T1 V1 T2 V2 ... Tn Vn)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::TOO_FEW_VALUES: - formattedMessage += - "Total values specified do not match the timesteps specified.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the PWL definition:\n"; - formattedMessage += "PWL(0 0 T1 V1 T2 V2 ... Tn Vn)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::INITIAL_PULSE_VALUE: - formattedMessage += "Invalid PULSE definition found.\n"; - formattedMessage += - "The value of " + message.value_or("") + " is expected to be 0\n"; - formattedMessage += "Please refer to the PULSE definition:\n"; - formattedMessage += "PULSE(0 V2 TD TR TF PW PER)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::PULSE_TOO_FEW_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for PULSE.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the PULSE definition:\n"; - formattedMessage += "PULSE(0 V2 TD TR TF PW PER)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::PULSE_VPEAK_ZERO: - formattedMessage += - "PULSE peak voltage is 0.0, this renders the function redundant.\n"; - formattedMessage += - "Program will continue but PULSE command is redundant."; - warning_message(formattedMessage); - break; - case FunctionErrors::PULSE_WIDTH_ZERO: - formattedMessage += - "PULSE width is 0.0, this renders the function redundant.\n"; - formattedMessage += - "Program will continue but PULSE command is redundant."; - warning_message(formattedMessage); - break; - case FunctionErrors::PULSE_REPEAT: - formattedMessage += - "PULSE repeat rate is 0.0, this is effectively a DC source.\n"; - formattedMessage += - "Program will continue, but this is most likely unwanted."; - warning_message(formattedMessage); - break; - case FunctionErrors::SIN_TOO_FEW_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for SIN.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the SIN definition:\n"; - formattedMessage += "SIN(VO VA FREQ TD THETA)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::SIN_TOO_MANY_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for SIN.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the SIN definition:\n"; - formattedMessage += "SIN(VO VA FREQ TD THETA)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::SIN_VA_ZERO: - formattedMessage += - "SIN amplitude is 0.0, this renders the function redundant.\n"; - formattedMessage += "Program will continue but SIN command is redundant."; - warning_message(formattedMessage); - break; - case FunctionErrors::CUS_TOO_FEW_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for CUS.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the CUS definition:\n"; - formattedMessage += "CUS(WaveFile.dat TS SF IM )"; - warning_message(formattedMessage); - break; - case FunctionErrors::CUS_TOO_MANY_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for CUS.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the CUS definition:\n"; - formattedMessage += "CUS(WaveFile.dat TS SF IM )"; - warning_message(formattedMessage); - break; - case FunctionErrors::CUS_SF_ZERO: - formattedMessage += - "CUS scale factor is 0.0, this renders the function redundant.\n"; - formattedMessage += "Program will continue but SIN command is redundant."; - warning_message(formattedMessage); - break; - case FunctionErrors::CUS_WF_NOT_FOUND: - formattedMessage += "CUS waveform file was not found.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Program will terminate."; - throw std::runtime_error(formattedMessage); - case FunctionErrors::CUS_UNKNOWN_IM: + case FunctionErrors::INITIAL_VALUES: + formattedMessage += "Invalid PWL definition found.\n"; + formattedMessage += + "The value of " + message.value_or("") + " is expected to be 0\n"; + formattedMessage += "Please refer to the PWL definition:\n"; + formattedMessage += "PWL(0 V0 T1 V1 T2 V2 ... Tn Vn)"; + warning_message(formattedMessage); + break; + case FunctionErrors::TOO_FEW_TIMESTEPS: + formattedMessage += + "Total timesteps specified do not match the values specified.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the PWL definition:\n"; + formattedMessage += "PWL(0 0 T1 V1 T2 V2 ... Tn Vn)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::TOO_FEW_VALUES: + formattedMessage += + "Total values specified do not match the timesteps specified.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the PWL definition:\n"; + formattedMessage += "PWL(0 0 T1 V1 T2 V2 ... Tn Vn)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::INITIAL_PULSE_VALUE: + formattedMessage += "Invalid PULSE definition found.\n"; + formattedMessage += + "The value of " + message.value_or("") + " is expected to be 0\n"; + formattedMessage += "Please refer to the PULSE definition:\n"; + formattedMessage += "PULSE(0 V2 TD TR TF PW PER)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::PULSE_TOO_FEW_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for PULSE.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the PULSE definition:\n"; + formattedMessage += "PULSE(0 V2 TD TR TF PW PER)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::PULSE_VPEAK_ZERO: + formattedMessage += + "PULSE peak voltage is 0.0, this renders the function redundant.\n"; + formattedMessage += + "Program will continue but PULSE command is redundant."; + warning_message(formattedMessage); + break; + case FunctionErrors::PULSE_WIDTH_ZERO: + formattedMessage += + "PULSE width is 0.0, this renders the function redundant.\n"; + formattedMessage += + "Program will continue but PULSE command is redundant."; + warning_message(formattedMessage); + break; + case FunctionErrors::PULSE_REPEAT: + formattedMessage += + "PULSE repeat rate is 0.0, this is effectively a DC source.\n"; + formattedMessage += + "Program will continue, but this is most likely unwanted."; + warning_message(formattedMessage); + break; + case FunctionErrors::SIN_TOO_FEW_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for SIN.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the SIN definition:\n"; + formattedMessage += "SIN(VO VA FREQ TD THETA)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::SIN_TOO_MANY_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for SIN.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the SIN definition:\n"; + formattedMessage += "SIN(VO VA FREQ TD THETA)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::SIN_VA_ZERO: + formattedMessage += + "SIN amplitude is 0.0, this renders the function redundant.\n"; + formattedMessage += "Program will continue but SIN command is redundant."; + warning_message(formattedMessage); + break; + case FunctionErrors::CUS_TOO_FEW_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for CUS.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the CUS definition:\n"; + formattedMessage += "CUS(WaveFile.dat TS SF IM )"; + warning_message(formattedMessage); + break; + case FunctionErrors::CUS_TOO_MANY_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for CUS.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the CUS definition:\n"; + formattedMessage += "CUS(WaveFile.dat TS SF IM )"; + warning_message(formattedMessage); + break; + case FunctionErrors::CUS_SF_ZERO: + formattedMessage += + "CUS scale factor is 0.0, this renders the function redundant.\n"; + formattedMessage += "Program will continue but SIN command is redundant."; + warning_message(formattedMessage); + break; + case FunctionErrors::CUS_WF_NOT_FOUND: + formattedMessage += "CUS waveform file was not found.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Program will terminate."; + throw std::runtime_error(formattedMessage); + case FunctionErrors::CUS_UNKNOWN_IM: formattedMessage += "CUS waveform has unknown interpolation method.\n"; formattedMessage += message.value_or("") + " specified.\n"; formattedMessage += "Program will terminate."; throw std::runtime_error(formattedMessage); - case FunctionErrors::NOISE_TOO_FEW_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for NOISE.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the NOISE definition:\n"; - formattedMessage += "NOISE(0 VA TSTEP TD)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::NOISE_TOO_MANY_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for NOISE.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the NOISE definition:\n"; - formattedMessage += "NOISE(0 VA TSTEP TD)"; - throw std::runtime_error(formattedMessage); - case FunctionErrors::NOISE_VO_ZERO: - formattedMessage += - "NOISE initial value is not 0.0, this needs to be zero.\n"; - formattedMessage += - "Program will continue but NOISE command is redundant."; - warning_message(formattedMessage); - break; - case FunctionErrors::NOISE_VA_ZERO: - formattedMessage += - "NOISE amplitude is 0.0, this renders the function redundant.\n"; - formattedMessage += - "Program will continue but NOISE command is redundant."; - warning_message(formattedMessage); - break; - case FunctionErrors::EXP_TOO_FEW_ARGUMENTS: - formattedMessage += - "Total arguments specified do not match the required for NOISE.\n"; - formattedMessage += message.value_or("") + " specified.\n"; - formattedMessage += "Please refer to the NOISE definition:\n"; - formattedMessage += - "EXP(V1 V2 TD1[0.0] TAU1[TSTEP] TD2[TD1+TSTEP] TAU2[TSTEP])"; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += - "Unknown function error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case FunctionErrors::NOISE_TOO_FEW_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for NOISE.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the NOISE definition:\n"; + formattedMessage += "NOISE(0 VA TSTEP TD)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::NOISE_TOO_MANY_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for NOISE.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the NOISE definition:\n"; + formattedMessage += "NOISE(0 VA TSTEP TD)"; + throw std::runtime_error(formattedMessage); + case FunctionErrors::NOISE_VO_ZERO: + formattedMessage += + "NOISE initial value is not 0.0, this needs to be zero.\n"; + formattedMessage += + "Program will continue but NOISE command is redundant."; + warning_message(formattedMessage); + break; + case FunctionErrors::NOISE_VA_ZERO: + formattedMessage += + "NOISE amplitude is 0.0, this renders the function redundant.\n"; + formattedMessage += + "Program will continue but NOISE command is redundant."; + warning_message(formattedMessage); + break; + case FunctionErrors::EXP_TOO_FEW_ARGUMENTS: + formattedMessage += + "Total arguments specified do not match the required for NOISE.\n"; + formattedMessage += message.value_or("") + " specified.\n"; + formattedMessage += "Please refer to the NOISE definition:\n"; + formattedMessage += + "EXP(V1 V2 TD1[0.0] TAU1[TSTEP] TD2[TD1+TSTEP] TAU2[TSTEP])"; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += + "Unknown function error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } [[noreturn]] void Errors::simulation_errors(SimulationErrors errorCode, - string_o message) { + string_o message) { std::string formattedMessage = "Simulation\n"; switch (errorCode) { - case SimulationErrors::JJCAP_NOT_FOUND: - formattedMessage += - "Capacitance for " + message.value_or("") + " could not be found.\n"; - formattedMessage += - "This is a bug and the developer should be contacted.\n"; - formattedMessage += "The program will abort."; - throw std::runtime_error(formattedMessage); - case SimulationErrors::JJICRIT_NOT_FOUND: - formattedMessage += - "Critical current value for " + message.value_or("") + - " could not be found.\n"; - formattedMessage += - "This is a bug and the developer should be contacted.\n"; - formattedMessage += "The program will abort."; - throw std::runtime_error(formattedMessage); - case SimulationErrors::JJPHASE_NODE_NOT_FOUND: - formattedMessage += - "Junction phase node not found for " + message.value_or("") + ".\n"; - formattedMessage += - "This is a bug and the developer should be contacted.\n"; - formattedMessage += "The program will abort."; - throw std::runtime_error(formattedMessage); - case SimulationErrors::INDUCTOR_CURRENT_NOT_FOUND: - formattedMessage += - "Inductor current not defined for " + message.value_or("") + ".\n"; - formattedMessage += "Matrix will have no solution.\n"; - formattedMessage += - "This is a bug and the developer should be contacted.\n"; - formattedMessage += "The program will abort."; - throw std::runtime_error(formattedMessage); - case SimulationErrors::MATRIX_SINGULAR: - formattedMessage += "Matrix is singular. Matrix will have no solution.\n"; - formattedMessage += "Please check the components in the netlist.\n"; - formattedMessage += "The program will abort."; - throw std::runtime_error(formattedMessage); - case SimulationErrors::PHASEGUESS_TOO_LARGE: - formattedMessage += - "Junction " + message.value_or("") + " has gone too far.\n"; - formattedMessage += "This is a result of integration error.\n"; - formattedMessage += "Please reduce the timestep and try again."; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += - "Unknown simulation error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case SimulationErrors::JJCAP_NOT_FOUND: + formattedMessage += + "Capacitance for " + message.value_or("") + " could not be found.\n"; + formattedMessage += + "This is a bug and the developer should be contacted.\n"; + formattedMessage += "The program will abort."; + throw std::runtime_error(formattedMessage); + case SimulationErrors::JJICRIT_NOT_FOUND: + formattedMessage += "Critical current value for " + message.value_or("") + + " could not be found.\n"; + formattedMessage += + "This is a bug and the developer should be contacted.\n"; + formattedMessage += "The program will abort."; + throw std::runtime_error(formattedMessage); + case SimulationErrors::JJPHASE_NODE_NOT_FOUND: + formattedMessage += + "Junction phase node not found for " + message.value_or("") + ".\n"; + formattedMessage += + "This is a bug and the developer should be contacted.\n"; + formattedMessage += "The program will abort."; + throw std::runtime_error(formattedMessage); + case SimulationErrors::INDUCTOR_CURRENT_NOT_FOUND: + formattedMessage += + "Inductor current not defined for " + message.value_or("") + ".\n"; + formattedMessage += "Matrix will have no solution.\n"; + formattedMessage += + "This is a bug and the developer should be contacted.\n"; + formattedMessage += "The program will abort."; + throw std::runtime_error(formattedMessage); + case SimulationErrors::MATRIX_SINGULAR: + formattedMessage += "Matrix is singular. Matrix will have no solution.\n"; + formattedMessage += "Please check the components in the netlist.\n"; + formattedMessage += "The program will abort."; + throw std::runtime_error(formattedMessage); + case SimulationErrors::PHASEGUESS_TOO_LARGE: + formattedMessage += + "Junction " + message.value_or("") + " has gone too far.\n"; + formattedMessage += "This is a result of integration error.\n"; + formattedMessage += "Please reduce the timestep and try again."; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += + "Unknown simulation error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } void Errors::parsing_errors(ParsingErrors errorCode, string_o message) { std::string formattedMessage = "Parsing\n"; switch (errorCode) { - case ParsingErrors::EXPRESSION_ARLEADY_DEFINED: - formattedMessage += - "Expression duplication: " + message.value_or("") + "\n"; - formattedMessage += "Replacing."; - warning_message(formattedMessage); - break; - case ParsingErrors::UNIDENTIFIED_PART: - formattedMessage += "The following variables were not found/defined.\n"; - formattedMessage += - "Please ensure that these variables exist within the netlist.\n"; - formattedMessage += "Variables: \n" + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ParsingErrors::MISMATCHED_PARENTHESIS: - formattedMessage += - "Mismatched parenthesis in expression: " + message.value_or("") + "\n"; - formattedMessage += "Please correct the expression before trying again."; - throw std::runtime_error(formattedMessage); - case ParsingErrors::INVALID_RPN: - formattedMessage += "Invalid RPN detected.\n"; - formattedMessage += - "This might be an algorithm fault or an incorrect expression parse.\n"; - formattedMessage += "The expression in question: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case ParsingErrors::INVALID_DECLARATION: - formattedMessage += - "Missing parameter declaration in: " + message.value_or("") + "\n"; - formattedMessage += - "Please ensure that a valid .PARAM definition is declared."; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += - "Unknown parsing error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case ParsingErrors::EXPRESSION_ARLEADY_DEFINED: + formattedMessage += + "Expression duplication: " + message.value_or("") + "\n"; + formattedMessage += "Replacing."; + warning_message(formattedMessage); + break; + case ParsingErrors::UNIDENTIFIED_PART: + formattedMessage += "The following variables were not found/defined.\n"; + formattedMessage += + "Please ensure that these variables exist within the netlist.\n"; + formattedMessage += "Variables: \n" + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ParsingErrors::MISMATCHED_PARENTHESIS: + formattedMessage += + "Mismatched parenthesis in expression: " + message.value_or("") + + "\n"; + formattedMessage += "Please correct the expression before trying again."; + throw std::runtime_error(formattedMessage); + case ParsingErrors::INVALID_RPN: + formattedMessage += "Invalid RPN detected.\n"; + formattedMessage += + "This might be an algorithm fault or an incorrect expression " + "parse.\n"; + formattedMessage += "The expression in question: " + message.value_or(""); + throw std::runtime_error(formattedMessage); + case ParsingErrors::INVALID_DECLARATION: + formattedMessage += + "Missing parameter declaration in: " + message.value_or("") + "\n"; + formattedMessage += + "Please ensure that a valid .PARAM definition is declared."; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += + "Unknown parsing error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } -[[noreturn]] void Errors::netlist_errors(NetlistErrors errorCode, string_o message) { +[[noreturn]] void Errors::netlist_errors(NetlistErrors errorCode, + string_o message) { std::string formattedMessage = "Netlist\n"; switch (errorCode) { - case NetlistErrors::NO_SUCH_NODE: - formattedMessage += - "Node \"" + message.value_or("") + "\" was not found in the netlist\n"; - formattedMessage += "Please check for any disconnections in the netlist"; - throw std::runtime_error(formattedMessage); - case NetlistErrors::MISSING_IO: - formattedMessage += "Missing I/O nodes for subcircuit:\n"; - formattedMessage += message.value_or("") + "\n"; - formattedMessage += "Please check for any disconnections in the netlist"; - throw std::runtime_error(formattedMessage); - default: - formattedMessage += - "Unknown netlist error: " + message.value_or("") + "\n"; - formattedMessage += "Please contact the developer."; - throw std::runtime_error(formattedMessage); + case NetlistErrors::NO_SUCH_NODE: + formattedMessage += "Node \"" + message.value_or("") + + "\" was not found in the netlist\n"; + formattedMessage += "Please check for any disconnections in the netlist"; + throw std::runtime_error(formattedMessage); + case NetlistErrors::MISSING_IO: + formattedMessage += "Missing I/O nodes for subcircuit:\n"; + formattedMessage += message.value_or("") + "\n"; + formattedMessage += "Please check for any disconnections in the netlist"; + throw std::runtime_error(formattedMessage); + default: + formattedMessage += + "Unknown netlist error: " + message.value_or("") + "\n"; + formattedMessage += "Please contact the developer."; + throw std::runtime_error(formattedMessage); } } void Errors::output_errors(OutputErrors errorCode, string_o message) { std::string formattedMessage = "Output\n"; switch (errorCode) { - case OutputErrors::CANNOT_OPEN_FILE: - formattedMessage += "Cannot open the requested file for output.\n"; - formattedMessage += - "Please ensure write permission for the file: " + message.value_or(""); - throw std::runtime_error(formattedMessage); - case OutputErrors::NOTHING_SPECIFIED: - formattedMessage += "Nothing specified to output.\n"; - formattedMessage += "Cannot create empty RAW file."; - warning_message(formattedMessage); - break; + case OutputErrors::CANNOT_OPEN_FILE: + formattedMessage += "Cannot open the requested file for output.\n"; + formattedMessage += "Please ensure write permission for the file: " + + message.value_or(""); + throw std::runtime_error(formattedMessage); + case OutputErrors::NOTHING_SPECIFIED: + formattedMessage += "Nothing specified to output.\n"; + formattedMessage += "Cannot create empty RAW file."; + warning_message(formattedMessage); + break; } } void Errors::verbosity_errors(VerbosityErrors errorCode, string_o message) { std::string formattedMessage = "Verbosity\n"; switch (errorCode) { - case VerbosityErrors::NO_SUCH_LEVEL: - formattedMessage += - "No such verbosity level: " + message.value_or("") + "\n"; - formattedMessage += "Continuing with maximum verbosity."; - warning_message(formattedMessage); - break; - case VerbosityErrors::INVALID_VERBOSITY_LEVEL: - formattedMessage += - "Invalid verbosity specified: " + message.value_or("") + "\n"; - formattedMessage += - "Please specify a valid level. Levels are 0, 1, 2, 3.\n"; - throw std::runtime_error(formattedMessage); + case VerbosityErrors::NO_SUCH_LEVEL: + formattedMessage += + "No such verbosity level: " + message.value_or("") + "\n"; + formattedMessage += "Continuing with maximum verbosity."; + warning_message(formattedMessage); + break; + case VerbosityErrors::INVALID_VERBOSITY_LEVEL: + formattedMessage += + "Invalid verbosity specified: " + message.value_or("") + "\n"; + formattedMessage += + "Please specify a valid level. Levels are 0, 1, 2, 3.\n"; + throw std::runtime_error(formattedMessage); } } - [[noreturn]] void Errors::oor() { std::cerr << "\nE: Out of range error. This is a bug." << std::endl; std::cerr << "E: Please contact the developer." << std::endl; diff --git a/src/Function.cpp b/src/Function.cpp index 087c0327..0a60824e 100644 --- a/src/Function.cpp +++ b/src/Function.cpp @@ -2,521 +2,506 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Function.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Parameters.hpp" -#include "spline.h" -#include -#include #include +#include #include +#include + +#include "JoSIM/Misc.hpp" +#include "JoSIM/Parameters.hpp" +#include "spline.h" using namespace JoSIM; -void Function::parse_function( - const std::string& str, const Input& iObj, const string_o& subckt) { - auto first = str.find('(') + 1; - auto last = str.find(')'); - std::string p = str.substr(first, last - first); - tokens_t t = Misc::tokenize(p, " ,"); - /* PWL(0 V0 T1 V1 T2 V2 ... TN VN) */ - if (str.find("PWL") != std::string::npos) { - fType_ = FunctionType::PWL; - parse_pwl(t, iObj, subckt); - } - /* PULSE(A1 A2 TD[0.0] TR[TSTEP] TF[TSTEP] PW[TSTOP] PER[TSTOP])*/ - else if (str.find("PULSE") != std::string::npos) { - fType_ = FunctionType::PULSE; - parse_pulse(t, iObj, subckt); - } - /* SIN(VO VA FREQ[1/TSTOP] TD[0.0] THETA[0.0]) */ - else if (str.find("SIN") != std::string::npos) { - fType_ = FunctionType::SINUSOID; - parse_sin(t, iObj, subckt); - } - /* CUS(WaveFile.dat TS[TSTEP] SF[1.0] IM[1] TD[0.0] PER[0]) */ - else if (str.find("CUS") != std::string::npos) { - fType_ = FunctionType::CUS; - parse_cus(t, iObj, subckt); - } - /* NOISE(VA TD TSTEP) */ - else if (str.find("NOISE") != std::string::npos) { - fType_ = FunctionType::NOISE; - parse_noise(t, iObj, subckt); - } - /* PWS(0 0 T1 V1 T2 V2 .. TN VN) */ - else if (str.find("PWS") != std::string::npos) { - fType_ = FunctionType::PWS; - parse_pwl(t, iObj, subckt); - } - /* EXP(V1 V2 TD1[0.0] TAU1[TSTEP] TD2[TD1+TSTEP] TAU2[TSTEP]) */ - else if (str.find("EXP") != std::string::npos) { - fType_ = FunctionType::EXP; - parse_exp(t, iObj, subckt); - } - /* DC VALUE */ - else if (str.find("DC") != std::string::npos) { - if (!std::isnan(parse_param( - Misc::tokenize(str).back(), iObj.parameters, subckt))) { - fType_ = FunctionType::DC; - parse_dc(t, iObj, subckt); - } - } - /* Only a value was provided? Assume user is trying to make a DC source */ - else if (!std::isnan(parse_param( - Misc::tokenize(str).back(), iObj.parameters, subckt))) { - fType_ = FunctionType::DC; - parse_dc(t, iObj, subckt); - } - else { - // Assume DC - } +void Function::parse_function(const std::string& str, const Input& iObj, + const string_o& subckt) { + auto first = str.find('(') + 1; + auto last = str.find(')'); + std::string p = str.substr(first, last - first); + tokens_t t = Misc::tokenize(p, " ,"); + /* PWL(0 V0 T1 V1 T2 V2 ... TN VN) */ + if (str.find("PWL") != std::string::npos) { + fType_ = FunctionType::PWL; + parse_pwl(t, iObj, subckt); + } + /* PULSE(A1 A2 TD[0.0] TR[TSTEP] TF[TSTEP] PW[TSTOP] PER[TSTOP])*/ + else if (str.find("PULSE") != std::string::npos) { + fType_ = FunctionType::PULSE; + parse_pulse(t, iObj, subckt); + } + /* SIN(VO VA FREQ[1/TSTOP] TD[0.0] THETA[0.0]) */ + else if (str.find("SIN") != std::string::npos) { + fType_ = FunctionType::SINUSOID; + parse_sin(t, iObj, subckt); + } + /* CUS(WaveFile.dat TS[TSTEP] SF[1.0] IM[1] TD[0.0] PER[0]) */ + else if (str.find("CUS") != std::string::npos) { + fType_ = FunctionType::CUS; + parse_cus(t, iObj, subckt); + } + /* NOISE(VA TD TSTEP) */ + else if (str.find("NOISE") != std::string::npos) { + fType_ = FunctionType::NOISE; + parse_noise(t, iObj, subckt); + } + /* PWS(0 0 T1 V1 T2 V2 .. TN VN) */ + else if (str.find("PWS") != std::string::npos) { + fType_ = FunctionType::PWS; + parse_pwl(t, iObj, subckt); + } + /* EXP(V1 V2 TD1[0.0] TAU1[TSTEP] TD2[TD1+TSTEP] TAU2[TSTEP]) */ + else if (str.find("EXP") != std::string::npos) { + fType_ = FunctionType::EXP; + parse_exp(t, iObj, subckt); + } + /* DC VALUE */ + else if (str.find("DC") != std::string::npos) { + if (!std::isnan( + parse_param(Misc::tokenize(str).back(), iObj.parameters, subckt))) { + fType_ = FunctionType::DC; + parse_dc(t, iObj, subckt); + } + } + /* Only a value was provided? Assume user is trying to make a DC source */ + else if (!std::isnan(parse_param(Misc::tokenize(str).back(), iObj.parameters, + subckt))) { + fType_ = FunctionType::DC; + parse_dc(t, iObj, subckt); + } else { + // Assume DC + } } -void Function::parse_pwl( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* PWL(0 V0 T1 V1 T2 V2 ... TN VN) */ - std::vector timesteps, values; - if (std::stod(t.at(0)) != 0.0) { - Errors::function_errors( - FunctionErrors::INITIAL_VALUES, t.at(0) + " & " + t.at(1)); - timesteps.push_back(0.0); - values.push_back(0.0); - } - for (int64_t i = 0; i < t.size(); i = i + 2) { - timesteps.push_back(Misc::modifier(t.at(i))); - } - for (int64_t i = 1; i < t.size(); i = i + 2) { - values.push_back(parse_param(t.at(i), iObj.parameters, s)); - } - if (timesteps.size() < values.size()) { - Errors::function_errors(FunctionErrors::TOO_FEW_TIMESTEPS, - std::to_string(timesteps.size()) + " timesteps & " + std::to_string( - timesteps.size()) + " values"); - } - if (timesteps.size() > values.size()) { - Errors::function_errors( - FunctionErrors::TOO_FEW_VALUES, std::to_string( - timesteps.size()) + " timesteps & " + std::to_string( - timesteps.size()) + " values"); - } - timeValues_ = timesteps; - ampValues_ = values; +void Function::parse_pwl(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* PWL(0 V0 T1 V1 T2 V2 ... TN VN) */ + std::vector timesteps, values; + if (std::stod(t.at(0)) != 0.0) { + Errors::function_errors(FunctionErrors::INITIAL_VALUES, + t.at(0) + " & " + t.at(1)); + timesteps.push_back(0.0); + values.push_back(0.0); + } + for (int64_t i = 0; i < t.size(); i = i + 2) { + timesteps.push_back(Misc::modifier(t.at(i))); + } + for (int64_t i = 1; i < t.size(); i = i + 2) { + values.push_back(parse_param(t.at(i), iObj.parameters, s)); + } + if (timesteps.size() < values.size()) { + Errors::function_errors(FunctionErrors::TOO_FEW_TIMESTEPS, + std::to_string(timesteps.size()) + " timesteps & " + + std::to_string(timesteps.size()) + " values"); + } + if (timesteps.size() > values.size()) { + Errors::function_errors(FunctionErrors::TOO_FEW_VALUES, + std::to_string(timesteps.size()) + " timesteps & " + + std::to_string(timesteps.size()) + " values"); + } + timeValues_ = timesteps; + ampValues_ = values; } -void Function::parse_pulse( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* PULSE(A1 A2 TD[0.0] TR[TSTEP] TF[TSTEP] PW[TSTOP] PER[TSTOP])*/ - if (t.size() < 2) { - Errors::function_errors( - FunctionErrors::PULSE_TOO_FEW_ARGUMENTS, std::to_string(t.size())); - } - // Step and stop time shorthand - const double& tstop = iObj.transSim.tstop(); - const double& tstep = iObj.transSim.tstep(); - // Set the 2 amplitudes - ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); - ampValues_.emplace_back(parse_param(t.at(1), iObj.parameters, s)); - // Set default values for optional arguments - timeValues_.emplace_back(0.0); - timeValues_.emplace_back(tstep); - timeValues_.emplace_back(tstep); - timeValues_.emplace_back(tstop); - timeValues_.emplace_back(tstop); - // Test if values exist - if (t.size() >= 3) - timeValues_.at(0) = parse_param(t.at(2), iObj.parameters, s); - if (t.size() >= 4) - timeValues_.at(1) = parse_param(t.at(3), iObj.parameters, s); - if (t.size() >= 5) - timeValues_.at(2) = parse_param(t.at(4), iObj.parameters, s); - if (t.size() >= 6) - timeValues_.at(3) = parse_param(t.at(5), iObj.parameters, s); - if (t.size() >= 7) - timeValues_.at(4) = parse_param(t.at(6), iObj.parameters, s); - if (iObj.argVerb) { - // If pulse width is 0.0 then there is no pulse, then useless so warn - if (timeValues_.at(3) == 0.0) { - Errors::function_errors(FunctionErrors::PULSE_WIDTH_ZERO, t.at(5)); - } - // If repeat time is 0.0 then impossible, so warn - if (timeValues_.at(4) == 0.0) { - Errors::function_errors(FunctionErrors::PULSE_REPEAT, t.at(6)); - } - } - // Store the stop time - timeValues_.emplace_back(tstop); +void Function::parse_pulse(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* PULSE(A1 A2 TD[0.0] TR[TSTEP] TF[TSTEP] PW[TSTOP] PER[TSTOP])*/ + if (t.size() < 2) { + Errors::function_errors(FunctionErrors::PULSE_TOO_FEW_ARGUMENTS, + std::to_string(t.size())); + } + // Step and stop time shorthand + const double& tstop = iObj.transSim.tstop(); + const double& tstep = iObj.transSim.tstep(); + // Set the 2 amplitudes + ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); + ampValues_.emplace_back(parse_param(t.at(1), iObj.parameters, s)); + // Set default values for optional arguments + timeValues_.emplace_back(0.0); + timeValues_.emplace_back(tstep); + timeValues_.emplace_back(tstep); + timeValues_.emplace_back(tstop); + timeValues_.emplace_back(tstop); + // Test if values exist + if (t.size() >= 3) + timeValues_.at(0) = parse_param(t.at(2), iObj.parameters, s); + if (t.size() >= 4) + timeValues_.at(1) = parse_param(t.at(3), iObj.parameters, s); + if (t.size() >= 5) + timeValues_.at(2) = parse_param(t.at(4), iObj.parameters, s); + if (t.size() >= 6) + timeValues_.at(3) = parse_param(t.at(5), iObj.parameters, s); + if (t.size() >= 7) + timeValues_.at(4) = parse_param(t.at(6), iObj.parameters, s); + if (iObj.argVerb) { + // If pulse width is 0.0 then there is no pulse, then useless so warn + if (timeValues_.at(3) == 0.0) { + Errors::function_errors(FunctionErrors::PULSE_WIDTH_ZERO, t.at(5)); + } + // If repeat time is 0.0 then impossible, so warn + if (timeValues_.at(4) == 0.0) { + Errors::function_errors(FunctionErrors::PULSE_REPEAT, t.at(6)); + } + } + // Store the stop time + timeValues_.emplace_back(tstop); } -void Function::parse_sin( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* SIN(VO VA FREQ[1/TSTOP] TD[0.0] THETA[0.0]) */ - if (t.size() < 2) { - Errors::function_errors( - FunctionErrors::SIN_TOO_FEW_ARGUMENTS, std::to_string(t.size())); - } - const double& tstop = iObj.transSim.tstop(); - // Set offset and peak amplitude - ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); - ampValues_.emplace_back(parse_param(t.at(1), iObj.parameters, s)); - if (iObj.argVerb) { - if (ampValues_.at(1) == 0.0) { - Errors::function_errors(FunctionErrors::SIN_VA_ZERO, t.at(1)); - } - } - // Set default optional values - timeValues_.emplace_back((1.0 / tstop)); - timeValues_.emplace_back(0.0); - timeValues_.emplace_back(0.0); - // Test if optional values exist - if (t.size() >= 3) - timeValues_.at(0) = parse_param(t.at(2), iObj.parameters, s); - if (t.size() >= 4) - timeValues_.at(1) = parse_param(t.at(3), iObj.parameters, s); - if (t.size() >= 5) - timeValues_.at(2) = parse_param(t.at(4), iObj.parameters, s); +void Function::parse_sin(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* SIN(VO VA FREQ[1/TSTOP] TD[0.0] THETA[0.0]) */ + if (t.size() < 2) { + Errors::function_errors(FunctionErrors::SIN_TOO_FEW_ARGUMENTS, + std::to_string(t.size())); + } + const double& tstop = iObj.transSim.tstop(); + // Set offset and peak amplitude + ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); + ampValues_.emplace_back(parse_param(t.at(1), iObj.parameters, s)); + if (iObj.argVerb) { + if (ampValues_.at(1) == 0.0) { + Errors::function_errors(FunctionErrors::SIN_VA_ZERO, t.at(1)); + } + } + // Set default optional values + timeValues_.emplace_back((1.0 / tstop)); + timeValues_.emplace_back(0.0); + timeValues_.emplace_back(0.0); + // Test if optional values exist + if (t.size() >= 3) + timeValues_.at(0) = parse_param(t.at(2), iObj.parameters, s); + if (t.size() >= 4) + timeValues_.at(1) = parse_param(t.at(3), iObj.parameters, s); + if (t.size() >= 5) + timeValues_.at(2) = parse_param(t.at(4), iObj.parameters, s); } -void Function::parse_cus( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* CUS(WaveFile.dat TS[TSTEP] SF[1.0] IM[1] TD[0.0] PER[0]) */ - if (t.size() < 2) { - Errors::function_errors( - FunctionErrors::CUS_TOO_FEW_ARGUMENTS, std::to_string(t.size())); - } - // First argument is required and is the wave file name - std::filesystem::path WFline(t.at(0)); - if (!WFline.has_parent_path()) { - WFline = std::filesystem::path(iObj.fileParentPath.value()); - WFline.append(t.at(0)); - } - if (!std::filesystem::exists(WFline)) { - auto pp = WFline.parent_path(); - auto stem = WFline.filename().string(); - std::transform(stem.begin(), stem.end(), stem.begin(), ::tolower); - WFline = std::filesystem::path(pp.append(stem)); - if (!std::filesystem::exists(WFline)) { - Errors::function_errors(FunctionErrors::CUS_WF_NOT_FOUND, t.at(0)); - } - } - std::vector WF; - const double& tstep = iObj.transSim.tstep(); - // Default values for the arguments - miscValues_.emplace_back(tstep); - miscValues_.emplace_back(1.0); - miscValues_.emplace_back(1); - miscValues_.emplace_back(0.0); - miscValues_.emplace_back(0); - // Test if optional values exist - if (t.size() >= 2) - miscValues_.at(0) = parse_param(t.at(1), iObj.parameters, s); - if (t.size() >= 3) - miscValues_.at(1) = parse_param(t.at(2), iObj.parameters, s); - if (t.size() >= 4) - miscValues_.at(2) = parse_param(t.at(3), iObj.parameters, s); - if (t.size() >= 5) - miscValues_.at(3) = parse_param(t.at(4), iObj.parameters, s); - if (t.size() >= 6) - miscValues_.at(4) = parse_param(t.at(5), iObj.parameters, s); +void Function::parse_cus(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* CUS(WaveFile.dat TS[TSTEP] SF[1.0] IM[1] TD[0.0] PER[0]) */ + if (t.size() < 2) { + Errors::function_errors(FunctionErrors::CUS_TOO_FEW_ARGUMENTS, + std::to_string(t.size())); + } + // First argument is required and is the wave file name + std::filesystem::path WFline(t.at(0)); + if (!WFline.has_parent_path()) { + WFline = std::filesystem::path(iObj.fileParentPath.value()); + WFline.append(t.at(0)); + } + if (!std::filesystem::exists(WFline)) { + auto pp = WFline.parent_path(); + auto stem = WFline.filename().string(); + std::transform(stem.begin(), stem.end(), stem.begin(), ::tolower); + WFline = std::filesystem::path(pp.append(stem)); + if (!std::filesystem::exists(WFline)) { + Errors::function_errors(FunctionErrors::CUS_WF_NOT_FOUND, t.at(0)); + } + } + std::vector WF; + const double& tstep = iObj.transSim.tstep(); + // Default values for the arguments + miscValues_.emplace_back(tstep); + miscValues_.emplace_back(1.0); + miscValues_.emplace_back(1); + miscValues_.emplace_back(0.0); + miscValues_.emplace_back(0); + // Test if optional values exist + if (t.size() >= 2) + miscValues_.at(0) = parse_param(t.at(1), iObj.parameters, s); + if (t.size() >= 3) + miscValues_.at(1) = parse_param(t.at(2), iObj.parameters, s); + if (t.size() >= 4) + miscValues_.at(2) = parse_param(t.at(3), iObj.parameters, s); + if (t.size() >= 5) + miscValues_.at(3) = parse_param(t.at(4), iObj.parameters, s); + if (t.size() >= 6) + miscValues_.at(4) = parse_param(t.at(5), iObj.parameters, s); - if (iObj.argVerb) { - if (miscValues_.at(1) == 0.0) { - Errors::function_errors(FunctionErrors::CUS_SF_ZERO, t.at(1)); - } - } - if (miscValues_.at(2) > 2 || miscValues_.at(2) < 0) { - Errors::function_errors(FunctionErrors::CUS_UNKNOWN_IM, - Misc::vector_to_string(t)); - } - std::ifstream wffile(std::filesystem::absolute(WFline)); - std::string line; - if (wffile.good()) { - getline(wffile, line); - } - else { - Errors::function_errors(FunctionErrors::CUS_WF_NOT_FOUND, line); - } - wffile.close(); - WF = Misc::tokenize(line, " ,;"); - for (int64_t i = 0; i < WF.size(); ++i) { - ampValues_.emplace_back(Misc::modifier(WF.at(i)) * miscValues_.at(1)); - } - if (miscValues_.at(0) < tstep) { - miscValues_.at(0) = tstep; - } - for (int i = 0; i < ampValues_.size(); ++i) { - timeValues_.emplace_back(miscValues_.at(3) + i * miscValues_.at(0)); - } - // Store the stop time - miscValues_.emplace_back(iObj.transSim.tstop()); + if (iObj.argVerb) { + if (miscValues_.at(1) == 0.0) { + Errors::function_errors(FunctionErrors::CUS_SF_ZERO, t.at(1)); + } + } + if (miscValues_.at(2) > 2 || miscValues_.at(2) < 0) { + Errors::function_errors(FunctionErrors::CUS_UNKNOWN_IM, + Misc::vector_to_string(t)); + } + std::ifstream wffile(std::filesystem::absolute(WFline)); + std::string line; + if (wffile.good()) { + getline(wffile, line); + } else { + Errors::function_errors(FunctionErrors::CUS_WF_NOT_FOUND, line); + } + wffile.close(); + WF = Misc::tokenize(line, " ,;"); + for (int64_t i = 0; i < WF.size(); ++i) { + ampValues_.emplace_back(Misc::modifier(WF.at(i)) * miscValues_.at(1)); + } + if (miscValues_.at(0) < tstep) { + miscValues_.at(0) = tstep; + } + for (int i = 0; i < ampValues_.size(); ++i) { + timeValues_.emplace_back(miscValues_.at(3) + i * miscValues_.at(0)); + } + // Store the stop time + miscValues_.emplace_back(iObj.transSim.tstop()); } -void Function::parse_noise( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* NOISE(VA TD[0.0] TSTEP[TSTEP]) */ - if (t.size() < 2) { - Errors::function_errors( - FunctionErrors::NOISE_TOO_FEW_ARGUMENTS, std::to_string(t.size())); - } - const double& tstep = iObj.transSim.tstep(); - // Set amplitudes - ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); - ampValues_.emplace_back(0.0); - // Default values for the arguments - timeValues_.emplace_back(0.0); - timeValues_.emplace_back(tstep); - // Test if optional values exist - if (t.size() >= 2) - timeValues_.at(0) = parse_param(t.at(1), iObj.parameters, s); - if (t.size() >= 3) - timeValues_.at(1) = parse_param(t.at(2), iObj.parameters, s); - miscValues_.emplace_back(0.0); - miscValues_.emplace_back( - ampValues_.at(0) * Misc::grand() / sqrt(2.0 * timeValues_.back())); - miscValues_.emplace_back(timeValues_.at(0)); - miscValues_.emplace_back(timeValues_.at(0) + timeValues_.at(1)); - if (iObj.argVerb) { - if (ampValues_.at(0) == 0.0) { - Errors::function_errors(FunctionErrors::NOISE_VA_ZERO, t.at(1)); - } - } +void Function::parse_noise(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* NOISE(VA TD[0.0] TSTEP[TSTEP]) */ + if (t.size() < 2) { + Errors::function_errors(FunctionErrors::NOISE_TOO_FEW_ARGUMENTS, + std::to_string(t.size())); + } + const double& tstep = iObj.transSim.tstep(); + // Set amplitudes + ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); + ampValues_.emplace_back(0.0); + // Default values for the arguments + timeValues_.emplace_back(0.0); + timeValues_.emplace_back(tstep); + // Test if optional values exist + if (t.size() >= 2) + timeValues_.at(0) = parse_param(t.at(1), iObj.parameters, s); + if (t.size() >= 3) + timeValues_.at(1) = parse_param(t.at(2), iObj.parameters, s); + miscValues_.emplace_back(0.0); + miscValues_.emplace_back(ampValues_.at(0) * Misc::grand() / + sqrt(2.0 * timeValues_.back())); + miscValues_.emplace_back(timeValues_.at(0)); + miscValues_.emplace_back(timeValues_.at(0) + timeValues_.at(1)); + if (iObj.argVerb) { + if (ampValues_.at(0) == 0.0) { + Errors::function_errors(FunctionErrors::NOISE_VA_ZERO, t.at(1)); + } + } } -void Function::parse_dc( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* DC VALUE */ - // Set amplitudes - ampValues_.emplace_back(parse_param(t.back(), iObj.parameters, s)); +void Function::parse_dc(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* DC VALUE */ + // Set amplitudes + ampValues_.emplace_back(parse_param(t.back(), iObj.parameters, s)); } -void Function::parse_exp( - const tokens_t& t, const Input& iObj, const string_o& s) { - /* EXP(V1 V2 TD1[0.0] TAU1[TSTEP] TD2[TD1+TSTEP] TAU2[TSTEP]) */ - if (t.size() < 2) { - Errors::function_errors( - FunctionErrors::EXP_TOO_FEW_ARGUMENTS, std::to_string(t.size())); - } - const double& tstep = iObj.transSim.tstep(); - // Set amplitudes - ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); - ampValues_.emplace_back(parse_param(t.at(1), iObj.parameters, s)); - // Default values for the arguments - timeValues_.emplace_back(0.0); - timeValues_.emplace_back(tstep); - timeValues_.emplace_back(tstep); - timeValues_.emplace_back(tstep); - // Test if optional values exist - if (t.size() >= 3) - timeValues_.at(0) = parse_param(t.at(2), iObj.parameters, s); - if (t.size() >= 4) - timeValues_.at(1) = parse_param(t.at(3), iObj.parameters, s); - if (t.size() >= 5) - timeValues_.at(2) = parse_param(t.at(4), iObj.parameters, s); - if (t.size() >= 6) - timeValues_.at(3) = parse_param(t.at(5), iObj.parameters, s); +void Function::parse_exp(const tokens_t& t, const Input& iObj, + const string_o& s) { + /* EXP(V1 V2 TD1[0.0] TAU1[TSTEP] TD2[TD1+TSTEP] TAU2[TSTEP]) */ + if (t.size() < 2) { + Errors::function_errors(FunctionErrors::EXP_TOO_FEW_ARGUMENTS, + std::to_string(t.size())); + } + const double& tstep = iObj.transSim.tstep(); + // Set amplitudes + ampValues_.emplace_back(parse_param(t.at(0), iObj.parameters, s)); + ampValues_.emplace_back(parse_param(t.at(1), iObj.parameters, s)); + // Default values for the arguments + timeValues_.emplace_back(0.0); + timeValues_.emplace_back(tstep); + timeValues_.emplace_back(tstep); + timeValues_.emplace_back(tstep); + // Test if optional values exist + if (t.size() >= 3) + timeValues_.at(0) = parse_param(t.at(2), iObj.parameters, s); + if (t.size() >= 4) + timeValues_.at(1) = parse_param(t.at(3), iObj.parameters, s); + if (t.size() >= 5) + timeValues_.at(2) = parse_param(t.at(4), iObj.parameters, s); + if (t.size() >= 6) + timeValues_.at(3) = parse_param(t.at(5), iObj.parameters, s); } double Function::return_pwl(double& x) { - // If x larger than the last timestep then assume last amplitude value - if (x >= timeValues_.back()) { - return ampValues_.back(); - // Else check within which range x falls - } - else { - for (int64_t i = 0; i < timeValues_.size() - 1; ++i) { - if (x >= timeValues_.at(i) && x < timeValues_.at(i + 1)) { - double& y2 = ampValues_.at(i + 1); - double& y1 = ampValues_.at(i); - double& x2 = timeValues_.at(i + 1); - double& x1 = timeValues_.at(i); - // Calculate function value and return it - return y1 + ((y2 - y1) / (x2 - x1)) * (x - x1); - } - } - } - return 0.0; + // If x larger than the last timestep then assume last amplitude value + if (x >= timeValues_.back()) { + return ampValues_.back(); + // Else check within which range x falls + } else { + for (int64_t i = 0; i < timeValues_.size() - 1; ++i) { + if (x >= timeValues_.at(i) && x < timeValues_.at(i + 1)) { + double& y2 = ampValues_.at(i + 1); + double& y1 = ampValues_.at(i); + double& x2 = timeValues_.at(i + 1); + double& x1 = timeValues_.at(i); + // Calculate function value and return it + return y1 + ((y2 - y1) / (x2 - x1)) * (x - x1); + } + } + } + return 0.0; } double Function::return_pulse(double& x) { - // Shorthand for the relevant time values - double& td = timeValues_.at(0); - double& tr = timeValues_.at(1); - double& tf = timeValues_.at(2); - double& pw = timeValues_.at(3); - double& per = timeValues_.at(4); - double& tstop = timeValues_.at(5); - double& alow = ampValues_.at(0); - double& ahigh = ampValues_.at(1); - auto val = alow; - if (x < td) return(val); - int64_t index = (x - td) / per; - auto time = x - td - index * per; - if (time < tr) { - val = alow + (ahigh - alow) * time / tr; - } - else if (time < tr + pw) { - val = ahigh; - } - else if (time < tr + pw + tf) { - val = ahigh + (alow - ahigh) * (time - tr - pw) / tf; - } - else { - val = alow; - } + // Shorthand for the relevant time values + double& td = timeValues_.at(0); + double& tr = timeValues_.at(1); + double& tf = timeValues_.at(2); + double& pw = timeValues_.at(3); + double& per = timeValues_.at(4); + double& tstop = timeValues_.at(5); + double& alow = ampValues_.at(0); + double& ahigh = ampValues_.at(1); + auto val = alow; + if (x < td) return (val); + int64_t index = (x - td) / per; + auto time = x - td - index * per; + if (time < tr) { + val = alow + (ahigh - alow) * time / tr; + } else if (time < tr + pw) { + val = ahigh; + } else if (time < tr + pw + tf) { + val = ahigh + (alow - ahigh) * (time - tr - pw) / tf; + } else { + val = alow; + } - return(val); + return (val); } double Function::return_sin(double& x) { - if (x >= timeValues_.at(1)) { - return ampValues_.at(0) + ampValues_.at(1) * - sin(2 * Constants::PI * timeValues_.at(0) * (x - timeValues_.at(1))) * - exp(-timeValues_.at(2) * (x - timeValues_.at(1))); - } - else return ampValues_.at(0); + if (x >= timeValues_.at(1)) { + return ampValues_.at(0) + + ampValues_.at(1) * + sin(2 * Constants::PI * timeValues_.at(0) * + (x - timeValues_.at(1))) * + exp(-timeValues_.at(2) * (x - timeValues_.at(1))); + } else + return ampValues_.at(0); } double Function::return_cus(double& x) { - auto& ts = miscValues_.at(0); - auto& sf = miscValues_.at(1); - int im = static_cast(std::round(miscValues_.at(2))); - auto& td = miscValues_.at(3); - bool per = static_cast(std::round(miscValues_.at(4))); - double& tstop = miscValues_.at(5); - if (x < td) { - return 0.0; - } - else { - double region = ampValues_.size() * ts; - double norm_x = (x - td); - if(per) norm_x = (x - td) - (std::floor(x / region) * region); - if (norm_x > region) return 0.0; - int idx = ampValues_.size() - 1; - for (int i = 0; i < ampValues_.size() - 1; ++i) { - if (norm_x >= i * ts && norm_x < (i + 1) * ts) { - idx = i; - break; - } - } - if (im == 0) { - return ampValues_.at(idx); - } - else if (im == 1) { - double& y2 = ampValues_.at(idx); - double y1 = 0.0; - if (idx != 0) y1 = ampValues_.at(idx - 1); - return y1 + ((y2 - y1) / ts) * (norm_x - (idx * ts)); - } - else if (im == 2) { - tk::spline s(timeValues_, ampValues_); - return s(norm_x); - } - } - return 0.0; + auto& ts = miscValues_.at(0); + auto& sf = miscValues_.at(1); + int im = static_cast(std::round(miscValues_.at(2))); + auto& td = miscValues_.at(3); + bool per = static_cast(std::round(miscValues_.at(4))); + double& tstop = miscValues_.at(5); + if (x < td) { + return 0.0; + } else { + double region = ampValues_.size() * ts; + double norm_x = (x - td); + if (per) norm_x = (x - td) - (std::floor(x / region) * region); + if (norm_x > region) return 0.0; + int idx = ampValues_.size() - 1; + for (int i = 0; i < ampValues_.size() - 1; ++i) { + if (norm_x >= i * ts && norm_x < (i + 1) * ts) { + idx = i; + break; + } + } + if (im == 0) { + return ampValues_.at(idx); + } else if (im == 1) { + double& y2 = ampValues_.at(idx); + double y1 = 0.0; + if (idx != 0) y1 = ampValues_.at(idx - 1); + return y1 + ((y2 - y1) / ts) * (norm_x - (idx * ts)); + } else if (im == 2) { + tk::spline s(timeValues_, ampValues_); + return s(norm_x); + } + } + return 0.0; } double Function::return_noise(double& x) { - if (x < timeValues_.front()) { - return ampValues_.at(1); - } - else { - if (x >= miscValues_.at(3)) { - miscValues_.at(0) = miscValues_.at(1); - miscValues_.at(1) = ampValues_.at(0) * - Misc::grand() / sqrt(2.0 * timeValues_.back()); - miscValues_.at(2) = miscValues_.at(3); - miscValues_.at(3) = miscValues_.at(2) + timeValues_.back(); - } - double& y2 = miscValues_.at(1); - double& y1 = miscValues_.at(0); - double& x2 = miscValues_.at(3); - double& x1 = miscValues_.at(2); - // Calculate function value and return it - return y1 + ((y2 - y1) / (x2 - x1)) * (x - x1); - } + if (x < timeValues_.front()) { + return ampValues_.at(1); + } else { + if (x >= miscValues_.at(3)) { + miscValues_.at(0) = miscValues_.at(1); + miscValues_.at(1) = + ampValues_.at(0) * Misc::grand() / sqrt(2.0 * timeValues_.back()); + miscValues_.at(2) = miscValues_.at(3); + miscValues_.at(3) = miscValues_.at(2) + timeValues_.back(); + } + double& y2 = miscValues_.at(1); + double& y1 = miscValues_.at(0); + double& x2 = miscValues_.at(3); + double& x1 = miscValues_.at(2); + // Calculate function value and return it + return y1 + ((y2 - y1) / (x2 - x1)) * (x - x1); + } } double Function::return_pws(double& x) { - // If x larger than the last timestep then assume last amplitude value - if (x >= timeValues_.back()) { - return ampValues_.back(); - // Else check within which range x falls - } - else { - for (int64_t i = 0; i < timeValues_.size() - 1; ++i) { - if (x >= timeValues_.at(i) && x < timeValues_.at(i + 1)) { - double& y2 = ampValues_.at(i + 1); - double& y1 = ampValues_.at(i); - double& x2 = timeValues_.at(i + 1); - double& x1 = timeValues_.at(i); - double period = (x2 - x1) * 2; - double ba; - if (y1 < y2) { - ba = (y2 - y1) / 2; - return y1 + ba * sin((2 * Constants::PI * - (x - (period / 4))) / period) + ba; - } - else if (y1 > y2) { - ba = (y1 - y2) / 2; - return y1 - ba * sin((2 * Constants::PI * - (x + (period / 4))) / period) - ba; - } - else if (y1 == y2) { - return y1; - } - } - } - } - return 0.0; + // If x larger than the last timestep then assume last amplitude value + if (x >= timeValues_.back()) { + return ampValues_.back(); + // Else check within which range x falls + } else { + for (int64_t i = 0; i < timeValues_.size() - 1; ++i) { + if (x >= timeValues_.at(i) && x < timeValues_.at(i + 1)) { + double& y2 = ampValues_.at(i + 1); + double& y1 = ampValues_.at(i); + double& x2 = timeValues_.at(i + 1); + double& x1 = timeValues_.at(i); + double period = (x2 - x1) * 2; + double ba; + if (y1 < y2) { + ba = (y2 - y1) / 2; + return y1 + + ba * sin((2 * Constants::PI * (x - (period / 4))) / period) + + ba; + } else if (y1 > y2) { + ba = (y1 - y2) / 2; + return y1 - + ba * sin((2 * Constants::PI * (x + (period / 4))) / period) - + ba; + } else if (y1 == y2) { + return y1; + } + } + } + } + return 0.0; } -double Function::return_dc() { - return ampValues_.back(); -} +double Function::return_dc() { return ampValues_.back(); } double Function::return_exp(double& x) { - // Shorthand for time values - double& a1 = ampValues_.at(0); - double& a2 = ampValues_.at(1); - double& td1 = timeValues_.at(0); - double& tau1 = timeValues_.at(1); - double& td2 = timeValues_.at(2); - double& tau2 = timeValues_.at(3); - if (x < td1) { - return ampValues_.at(0); - } - else if (x >= td1 && x < td2) { - return a1 + (a2 - a1) * (1 - exp(-(x - td1) / tau1)); - } - else if (x >= td2) { - return a1 + (a2 - a1) * (1 - exp(-(x - td1) / tau1)) + - (a1 - a2) * (1 - exp(-(x - td2) / tau2)); - } - return 0.0; + // Shorthand for time values + double& a1 = ampValues_.at(0); + double& a2 = ampValues_.at(1); + double& td1 = timeValues_.at(0); + double& tau1 = timeValues_.at(1); + double& td2 = timeValues_.at(2); + double& tau2 = timeValues_.at(3); + if (x < td1) { + return ampValues_.at(0); + } else if (x >= td1 && x < td2) { + return a1 + (a2 - a1) * (1 - exp(-(x - td1) / tau1)); + } else if (x >= td2) { + return a1 + (a2 - a1) * (1 - exp(-(x - td1) / tau1)) + + (a1 - a2) * (1 - exp(-(x - td2) / tau2)); + } + return 0.0; } double Function::value(double x) { - switch (fType_) { - case FunctionType::PWL: - return return_pwl(x); - case FunctionType::PULSE: - return return_pulse(x); - case FunctionType::SINUSOID: - return return_sin(x); - case FunctionType::CUS: - return return_cus(x); - case FunctionType::NOISE: - return return_noise(x); - case FunctionType::PWS: - return return_pws(x); - case FunctionType::DC: - return return_dc(); - case FunctionType::EXP: - return return_exp(x); - default: - return 0.0; - } + switch (fType_) { + case FunctionType::PWL: + return return_pwl(x); + case FunctionType::PULSE: + return return_pulse(x); + case FunctionType::SINUSOID: + return return_sin(x); + case FunctionType::CUS: + return return_cus(x); + case FunctionType::NOISE: + return return_noise(x); + case FunctionType::PWS: + return return_pws(x); + case FunctionType::DC: + return return_dc(); + case FunctionType::EXP: + return return_exp(x); + default: + return 0.0; + } } -void Function::ampValues(std::vector values) { - ampValues_ = values; -} \ No newline at end of file +void Function::ampValues(std::vector values) { ampValues_ = values; } \ No newline at end of file diff --git a/src/IV.cpp b/src/IV.cpp index 078c26cc..d4f7d581 100644 --- a/src/IV.cpp +++ b/src/IV.cpp @@ -2,14 +2,15 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/IV.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Parameters.hpp" #include #include #include +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/Parameters.hpp" + using namespace JoSIM; IV::IV(const Input iObj) { @@ -23,7 +24,7 @@ IV::IV(const Input iObj) { void IV::setup_iv(const tokens_t& i, const Input& iObj) { if (i.size() < 4) { Errors::control_errors(ControlErrors::INVALID_IV_COMMAND, - Misc::vector_to_string(i)); + Misc::vector_to_string(i)); } // Model can be part of a subcircuit so find subcircuit and model name tokens_t t = Misc::tokenize(i.at(1), ".|"); @@ -35,19 +36,17 @@ void IV::setup_iv(const tokens_t& i, const Input& iObj) { // Check to see if model exists if (iObj.netlist.models.count(std::make_pair(model, subc)) == 0) { Errors::control_errors(ControlErrors::IV_MODEL_NOT_FOUND, - model + ((subc) ? "|" + subc.value() : "")); + model + ((subc) ? "|" + subc.value() : "")); } // Determine the maximum current to which to draw the IV curve double maxC = parse_param(i.at(2), iObj.parameters); // Create an input object for this simulation Input ivInp = iObj; ivInp.controls.clear(); - tokens_t jj = { "B01", "1", "0", model, "AREA=1" }; - tokens_t ib = { "IB01", "0", "1", "PWL(0", "0", "10P", "0", "50P", "2.5U)" }; - ivInp.netlist.expNetlist = { - std::make_pair(jj, subc), - std::make_pair(ib, std::nullopt) - }; + tokens_t jj = {"B01", "1", "0", model, "AREA=1"}; + tokens_t ib = {"IB01", "0", "1", "PWL(0", "0", "10P", "0", "50P", "2.5U)"}; + ivInp.netlist.expNetlist = {std::make_pair(jj, subc), + std::make_pair(ib, std::nullopt)}; ivInp.transSim.tstep(0.05E-12); ivInp.transSim.tstop(500E-12); ivInp.argAnal = JoSIM::AnalysisType::Voltage; @@ -63,38 +62,38 @@ void IV::setup_iv(const tokens_t& i, const Input& iObj) { write_iv(iv_data, path.string()); } -std::vector> IV::generate_iv(double maxC, - Input ivInp) { +std::vector> IV::generate_iv(double maxC, + Input ivInp) { std::vector> iv_data; double currentIncrement = 25E-7; double currentCurr = 0.0; Matrix ivMat; ivMat.create_matrix(ivInp); - while(currentCurr <= maxC) { + while (currentCurr <= maxC) { // Create a matrix object using the input object currentCurr += currentIncrement; - ivMat.sourcegen.back().ampValues({ 0, 0, currentCurr }); + ivMat.sourcegen.back().ampValues({0, 0, currentCurr}); iv_data.emplace_back(do_simulate(ivInp, ivMat)); ivInp.transSim.tstep(0.05E-12); } while (currentCurr >= 0) { // Create a matrix object using the input object currentCurr -= currentIncrement; - ivMat.sourcegen.back().ampValues({ 0, maxC, currentCurr }); + ivMat.sourcegen.back().ampValues({0, maxC, currentCurr}); iv_data.emplace_back(do_simulate(ivInp, ivMat)); ivInp.transSim.tstep(0.05E-12); } while (currentCurr >= -maxC) { // Create a matrix object using the input object currentCurr -= currentIncrement; - ivMat.sourcegen.back().ampValues({ 0, 0, currentCurr }); + ivMat.sourcegen.back().ampValues({0, 0, currentCurr}); iv_data.emplace_back(do_simulate(ivInp, ivMat)); ivInp.transSim.tstep(0.05E-12); } while (currentCurr <= 0) { // Create a matrix object using the input object currentCurr += currentIncrement; - ivMat.sourcegen.back().ampValues({ 0, -maxC, currentCurr }); + ivMat.sourcegen.back().ampValues({0, -maxC, currentCurr}); iv_data.emplace_back(do_simulate(ivInp, ivMat)); ivInp.transSim.tstep(0.05E-12); } @@ -116,7 +115,7 @@ std::pair IV::do_simulate(Input& ivInp, Matrix& ivMat) { } void IV::write_iv(std::vector>& iv_data, - const std::string& output_path) { + const std::string& output_path) { auto path = std::filesystem::path(output_path); std::ofstream outfile(path.string()); outfile << std::setprecision(6); diff --git a/src/Inductor.cpp b/src/Inductor.cpp index 4f012224..4a4b2c16 100644 --- a/src/Inductor.cpp +++ b/src/Inductor.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Inductor.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -27,15 +28,15 @@ using namespace JoSIM; ⎣ 1 -1 -L(2e/hbar)⎦ ⎣Io⎦ ⎣ 0⎦ */ -Inductor::Inductor( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, nodeconnections& nc, - Input& iObj, Spread spread, int64_t& bi) { +Inductor::Inductor(const std::pair& s, + const NodeConfig& ncon, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + Input& iObj, Spread spread, int64_t& bi) { double spr = 1.0; for (auto i : s.first) { if (i.find("SPREAD=") != std::string::npos) { - spr = - parse_param(i.substr(i.find("SPREAD=") + 7), iObj.parameters, s.second); + spr = parse_param(i.substr(i.find("SPREAD=") + 7), iObj.parameters, + s.second); } } at_ = iObj.argAnal; @@ -43,16 +44,15 @@ Inductor::Inductor( In2_ = 0.0; // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); // Add the label to the known labels list lm.emplace(s.first.at(0)); // Set the value (Inductance), this should be the 4th token - netlistInfo.value_ = - spread.spread_value( + netlistInfo.value_ = spread.spread_value( parse_param(s.first.at(3), iObj.parameters, s.second), Spread::IND, spr); // Set the node configuration type indexInfo.nodeConfig_ = ncon; @@ -66,16 +66,15 @@ Inductor::Inductor( if (at_ == AnalysisType::Voltage) { // If voltage mode analysis then append -(3/2) * (L/h) matrixInfo.nonZeros_.emplace_back( - -(3.0 / 2.0) * (netlistInfo.value_ / iObj.transSim.tstep())); + -(3.0 / 2.0) * (netlistInfo.value_ / iObj.transSim.tstep())); } else if (at_ == AnalysisType::Phase) { // If phase mdoe analysis then append -(L/σ) - matrixInfo.nonZeros_.emplace_back( - -netlistInfo.value_ / Constants::SIGMA); + matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_ / Constants::SIGMA); } } -void Inductor::add_mutualInductance( - const double& m, const AnalysisType& at, const double& h, const int64_t& ci) { +void Inductor::add_mutualInductance(const double& m, const AnalysisType& at, + const double& h, const int64_t& ci) { // Adds the mutual inductance to the non zero vector if (at == AnalysisType::Voltage) { // If voltage mode then add -(3/2) * (m/h) diff --git a/src/Input.cpp b/src/Input.cpp index f436b1bb..892a957d 100644 --- a/src/Input.cpp +++ b/src/Input.cpp @@ -2,25 +2,26 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Input.hpp" -#include "JoSIM/ProgressBar.hpp" +#include +#include +#include #include #include #include -#include -#include #include -#include + +#include "JoSIM/ProgressBar.hpp" using namespace JoSIM; -std::vector Input::read_input( - LineInput& input, string_o fileName) { - //When the standard input is selected, "fileName" will be in the nullopt state. - if(fileName != std::nullopt){ +std::vector Input::read_input(LineInput& input, string_o fileName) { + // When the standard input is selected, "fileName" will be in the nullopt + // state. + if (fileName != std::nullopt) { if (std::filesystem::path(fileName.value()).has_parent_path()) { fileParentPath = - std::filesystem::path(fileName.value()).parent_path().string(); + std::filesystem::path(fileName.value()).parent_path().string(); } } // Variable to store the read line @@ -42,9 +43,10 @@ std::vector Input::read_input( tokens = Misc::tokenize(line); // Uppercase just the first token for ".INCLUDE" and ".FILE" check std::transform(tokens.begin(), tokens.begin() + 1, tokens.begin(), - [](std::string& c) -> std::string { - std::transform(c.begin(), c.end(), c.begin(), toupper); - return c; }); + [](std::string& c) -> std::string { + std::transform(c.begin(), c.end(), c.begin(), toupper); + return c; + }); // If the line contains a "INCLUDE" statement if (tokens.at(0) == ".INCLUDE" || tokens.at(0) == "INCLUDE") { // Variable to store path to file to include @@ -53,38 +55,41 @@ std::vector Input::read_input( if (fileName) { // Sanity check to prevent cyclic includes if (std::filesystem::path(fileName.value()).c_str() == - std::filesystem::path(fileName.value()).parent_path().append( - tokens.at(1)).c_str()) { + std::filesystem::path(fileName.value()) + .parent_path() + .append(tokens.at(1)) + .c_str()) { Errors::input_errors(InputErrors::CYCLIC_INCLUDE, fileName); } - includeFile = std::filesystem::path( - fileName.value()).parent_path().append(tokens.at(1)).string(); + includeFile = std::filesystem::path(fileName.value()) + .parent_path() + .append(tokens.at(1)) + .string(); } else { includeFile = - std::filesystem::current_path().append(tokens.at(1)).string(); + std::filesystem::current_path().append(tokens.at(1)).string(); } // Create a new LineInput variable for the included file FileInput file(includeFile); // Attempt to read the contents of the included file std::vector tempInclude = - Input::read_input(file, includeFile); + Input::read_input(file, includeFile); // Insert the lines from the included file in place - fileLines.insert( - fileLines.end(), tempInclude.begin(), tempInclude.end()); + fileLines.insert(fileLines.end(), tempInclude.begin(), + tempInclude.end()); // If the line contains a "FILE" statement } else if (tokens.at(0) == ".FILE" || tokens.at(0) == "FILE") { // Ensure there is a second token if (tokens.size() < 2) { Errors::control_errors(ControlErrors::INVALID_FILE_COMMAND, line); } else { - // Sanity check, if parent path of output file is empty then - // change path to input file path, otherwise file is written + // Sanity check, if parent path of output file is empty then + // change path to input file path, otherwise file is written // in executable location auto path = std::filesystem::path(tokens.at(1)); if (!path.has_parent_path() && fileParentPath) { - path = - std::filesystem::path( - fileParentPath.value()).append(tokens.at(1)); + path = std::filesystem::path(fileParentPath.value()) + .append(tokens.at(1)); } output_files.emplace_back(OutputFile(path.string())); } @@ -96,15 +101,16 @@ std::vector Input::read_input( } else { // Transform the entire line to upper case std::transform(tokens.begin() + 1, tokens.end(), tokens.begin() + 1, - [](std::string& c) -> std::string { - std::transform(c.begin(), c.end(), c.begin(), toupper); - return c; }); + [](std::string& c) -> std::string { + std::transform(c.begin(), c.end(), c.begin(), toupper); + return c; + }); // If the line starts with a '+' append it to the previous line. if (tokens.at(0).at(0) == '+') { // Remove the '+' tokens.at(0) = tokens.at(0).substr(1); - fileLines.back().insert( - fileLines.back().end(), tokens.begin(), tokens.end()); + fileLines.back().insert(fileLines.back().end(), tokens.begin(), + tokens.end()); // Add the line to the read in lines variable } else { fileLines.emplace_back(tokens); @@ -179,7 +185,7 @@ void Input::parse_input(string_o fileName) { // Populate the a subcircuit at given name with its IO nodes for (int64_t j = 2; j < fileLines.at(i).size(); ++j) { netlist.subcircuits[subckt.value()].io.push_back( - fileLines.at(i).at(j)); + fileLines.at(i).at(j)); } // Complain if no IO is found } else { @@ -204,7 +210,7 @@ void Input::parse_input(string_o fileName) { // If model, add model to models list } else if (::strcmp(fileLines.at(i).front().c_str(), ".MODEL") == 0) { netlist.models[std::make_pair(fileLines.at(i).at(1), subckt)] = - fileLines.at(i); + fileLines.at(i); // If neither of these, normal control, add to controls list } else { // Controls cannot exist within a subcircuit @@ -226,7 +232,7 @@ void Input::parse_input(string_o fileName) { // If model, add to models list } else if (::strcmp(fileLines.at(i).front().c_str(), "MODEL") == 0) { netlist.models[std::make_pair(fileLines.at(i).at(1), subckt)] = - fileLines.at(i); + fileLines.at(i); // If neither, add to controls list } else { if (!subckt) { @@ -240,7 +246,7 @@ void Input::parse_input(string_o fileName) { // If subcircuit flag, add line to relevant subcircuit if (subckt) { netlist.subcircuits[subckt.value()].lines.push_back( - std::make_pair(fileLines.at(i), subckt)); + std::make_pair(fileLines.at(i), subckt)); // If not, add line to main design } else { netlist.maindesign.push_back(fileLines.at(i)); @@ -261,9 +267,8 @@ void Input::parse_input(string_o fileName) { void Input::syntax_check_controls(std::vector& controls) { // This will simply check controls, complaining if any are not allowed - std::vector v = - { "PRINT", "TRAN", "SAVE", "PLOT", "END", - "TEMP", "NEB", "SPREAD", "FILE", "IV" }; + std::vector v = {"PRINT", "TRAN", "SAVE", "PLOT", "END", + "TEMP", "NEB", "SPREAD", "FILE", "IV"}; for (auto i : controls) { if (std::find(v.begin(), v.end(), i.at(0)) == v.end()) { Errors::input_errors(InputErrors::UNKNOWN_CONTROL, i.at(0)); diff --git a/src/JJ.cpp b/src/JJ.cpp index b279cf7e..c5ae17b6 100644 --- a/src/JJ.cpp +++ b/src/JJ.cpp @@ -2,13 +2,14 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/JJ.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" -#include "JoSIM/Noise.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/Noise.hpp" + using namespace JoSIM; /* @@ -38,10 +39,9 @@ using namespace JoSIM; RHS1 = (4/3)φn-1 - (1/3)φn-2 */ -JJ::JJ( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, nodeconnections& nc, - Input& iObj, Spread& spread, int64_t& bi) { +JJ::JJ(const std::pair& s, const NodeConfig& ncon, + const nodemap& nm, std::unordered_set& lm, + nodeconnections& nc, Input& iObj, Spread& spread, int64_t& bi) { double spr = 1.0; tokens_t t; for (int64_t i = 3; i < s.first.size(); ++i) { @@ -54,10 +54,12 @@ JJ::JJ( neb_ = parse_param(ti.substr(4), iObj.parameters, s.second); } else if (ti.rfind("AREA=", 0) == 0) { area_ = spread.spread_value( - parse_param(ti.substr(5), iObj.parameters, s.second), Spread::JJ, spr); + parse_param(ti.substr(5), iObj.parameters, s.second), Spread::JJ, + spr); } else if (ti.rfind("IC=", 0) == 0) { Ic_ = spread.spread_value( - parse_param(ti.substr(3), iObj.parameters, s.second), Spread::JJ, spr); + parse_param(ti.substr(3), iObj.parameters, s.second), Spread::JJ, + spr); } else { t.emplace_back(ti); } @@ -75,8 +77,8 @@ JJ::JJ( state_ = 0; // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -103,12 +105,13 @@ JJ::JJ( // Set the non zero, column index and row pointer vectors set_matrix_info(); if (temp_) { - spAmp_ = Noise::determine_spectral_amplitude( - this->model_.r0(), temp_.value()); + spAmp_ = + Noise::determine_spectral_amplitude(this->model_.r0(), temp_.value()); Function tnoise; - tnoise.parse_function("NOISE(" + - Misc::precise_to_string(spAmp_.value()) + ", 0.0, " + - Misc::precise_to_string(1.0 / neb_.value()) + ")", iObj, s.second); + tnoise.parse_function("NOISE(" + Misc::precise_to_string(spAmp_.value()) + + ", 0.0, " + + Misc::precise_to_string(1.0 / neb_.value()) + ")", + iObj, s.second); thermalNoise = tnoise; } } @@ -130,38 +133,38 @@ double JJ::normal_impedance() { void JJ::set_matrix_info() { switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); - matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); - matrixInfo.rowPointer_.emplace_back(3); - break; - case NodeConfig::GND: - matrixInfo.rowPointer_.emplace_back(1); - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); + matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); + matrixInfo.rowPointer_.emplace_back(3); + break; + case NodeConfig::GND: + matrixInfo.rowPointer_.emplace_back(1); + break; } matrixInfo.nonZeros_.emplace_back(-phaseConst_); hDepPos_ = matrixInfo.nonZeros_.size() - 1; matrixInfo.columnIndex_.emplace_back(variableIndex_); if (at_ == AnalysisType::Voltage) { - matrixInfo.nonZeros_.insert( - matrixInfo.nonZeros_.end(), - matrixInfo.nonZeros_.begin(), matrixInfo.nonZeros_.end()); + matrixInfo.nonZeros_.insert(matrixInfo.nonZeros_.end(), + matrixInfo.nonZeros_.begin(), + matrixInfo.nonZeros_.end()); matrixInfo.nonZeros_.back() = -1 / subgap_impedance(); - matrixInfo.columnIndex_.insert( - matrixInfo.columnIndex_.end(), - matrixInfo.columnIndex_.begin(), matrixInfo.columnIndex_.end()); + matrixInfo.columnIndex_.insert(matrixInfo.columnIndex_.end(), + matrixInfo.columnIndex_.begin(), + matrixInfo.columnIndex_.end()); matrixInfo.columnIndex_.back() = indexInfo.currentIndex_.value(); matrixInfo.rowPointer_.emplace_back(matrixInfo.rowPointer_.back()); } else if (at_ == AnalysisType::Phase) { @@ -173,9 +176,9 @@ void JJ::set_matrix_info() { } } -void JJ::set_model( - const tokens_t& t, const vector_pair_t& models, - const string_o& subc) { +void JJ::set_model(const tokens_t& t, + const vector_pair_t& models, + const string_o& subc) { bool found = false; // Loop through all models for (auto& i : models) { @@ -199,31 +202,31 @@ void JJ::set_model( // If no model was found if (!found) { // Complain about it - Errors::invalid_component_errors( - ComponentErrors::MODEL_NOT_DEFINED, Misc::vector_to_string(t)); + Errors::invalid_component_errors(ComponentErrors::MODEL_NOT_DEFINED, + Misc::vector_to_string(t)); } // Change the area if ic was defined if (Ic_) { area_ = Ic_.value() / model_.ic(); } - // Set the model critical current for this JJ instance + // Set the model critical current for this JJ instance model_.ic(model_.ic() * area_); if (model_.tDep()) { // Set the Del0 parameter del0_ = 1.76 * Constants::BOLTZMANN * model_.tc(); // Set the del parameter - del_ = del0_ * sqrt(cos((Constants::PI / 2) * - (model_.t() / model_.tc()) * (model_.t() / model_.tc()))); + del_ = del0_ * sqrt(cos((Constants::PI / 2) * (model_.t() / model_.tc()) * + (model_.t() / model_.tc()))); // Set the temperature dependent normal resistance model_.rn(((Constants::PI * del_) / (2 * Constants::EV * model_.ic())) * - tanh(del_ / (2 * Constants::BOLTZMANN * model_.t()))); + tanh(del_ / (2 * Constants::BOLTZMANN * model_.t()))); } else { - // Set the model normal resistance for this JJ instance + // Set the model normal resistance for this JJ instance model_.rn(model_.rn() / area_); } // Set the model capacitance for this JJ instance model_.c(model_.c() * area_); - // Set the model subgap resistance for this JJ instance + // Set the model subgap resistance for this JJ instance model_.r0(model_.r0() / area_); // Set the lower boundary for the transition region lowerB_ = model_.vg() - 0.5 * model_.deltaV(); @@ -244,8 +247,8 @@ bool JJ::update_value(const double& v) { if (fabs(v) < lowerB_) { // Set temperature resistance if (this->temp_) { - thermalNoise.value().ampValues().at(0) = - Noise::determine_spectral_amplitude(this->model_.r0(), temp_.value()); + thermalNoise.value().ampValues().at(0) = + Noise::determine_spectral_amplitude(this->model_.r0(), temp_.value()); } // Set the transition current to 0 it_ = 0.0; @@ -286,7 +289,7 @@ bool JJ::update_value(const double& v) { // Set temperature resistance if (this->temp_) { thermalNoise.value().ampValues().at(0) = - Noise::determine_spectral_amplitude(this->model_.rn(), temp_.value()); + Noise::determine_spectral_amplitude(this->model_.rn(), temp_.value()); } // Reset the transition current, transition has passed. it_ = 0.0; diff --git a/src/LUSolve.cpp b/src/LUSolve.cpp index eccd1dfe..e758f01f 100644 --- a/src/LUSolve.cpp +++ b/src/LUSolve.cpp @@ -15,14 +15,15 @@ LUSolve::LUSolve() { } void LUSolve::create_matrix(int64_t shape, std::vector& nz, - std::vector& ci, std::vector& rp) { - bool do_allocation = (allocated == false || m != shape || - n != shape || nnz != nz.size()); + std::vector& ci, + std::vector& rp) { + bool do_allocation = + (allocated == false || m != shape || n != shape || nnz != nz.size()); m = n = shape; nnz = nz.size(); if (do_allocation) { - dCreate_CompCol_Matrix(&A, m, n, nnz, &nz.front(), &ci.front(), - &rp.front(), SLU_NC, SLU_D, SLU_GE); + dCreate_CompCol_Matrix(&A, m, n, nnz, &nz.front(), &ci.front(), &rp.front(), + SLU_NC, SLU_D, SLU_GE); if (!(rhsb = doubleMalloc(m * nrhs))) ABORT("Malloc fails for rhsb[]."); if (!(rhsx = doubleMalloc(m * nrhs))) ABORT("Malloc fails for rhsx[]."); dCreate_Dense_Matrix(&B, m, nrhs, rhsb, m, SLU_DN, SLU_D, SLU_GE); @@ -53,8 +54,8 @@ bool LUSolve::is_stable() { void LUSolve::factorize(bool symbolic) { options.Fact = symbolic ? SamePattern_SameRowPerm : DOFACT; - dgssvx(&options, &A, perm_c, perm_r, etree, equed, R, C, &L, &U, work, lwork, - &B, &X, &rpg, &rcond, ferr, berr, &Glu, &mem_usage, &stat, &info); + dgssvx(&options, &A, perm_c, perm_r, etree, equed, R, C, &L, &U, work, lwork, + &B, &X, &rpg, &rcond, ferr, berr, &Glu, &mem_usage, &stat, &info); options.Fact = FACTORED; constructed = true; } @@ -63,9 +64,9 @@ void LUSolve::solve(std::vector& x) { if (!constructed) { ABORT("Preconditioner not constructed."); } - DNformat LHSstore = { static_cast(x.size()), &x.front() }; - SuperMatrix LHSmat = { SLU_DN, SLU_D, SLU_GE, static_cast(x.size()), - 1, &LHSstore }; + DNformat LHSstore = {static_cast(x.size()), &x.front()}; + SuperMatrix LHSmat = {SLU_DN, SLU_D, SLU_GE, static_cast(x.size()), + 1, &LHSstore}; dgstrs(trans, &L, &U, perm_c, perm_r, &LHSmat, &stat, &info); } diff --git a/src/Matrix.cpp b/src/Matrix.cpp index c7856dc5..c11a3633 100644 --- a/src/Matrix.cpp +++ b/src/Matrix.cpp @@ -2,16 +2,17 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Matrix.hpp" -#include "JoSIM/Misc.hpp" + +#include +#include +#include + #include "JoSIM/Constants.hpp" #include "JoSIM/Errors.hpp" #include "JoSIM/Function.hpp" -#include "JoSIM/ProgressBar.hpp" +#include "JoSIM/Misc.hpp" #include "JoSIM/Noise.hpp" - -#include -#include -#include +#include "JoSIM/ProgressBar.hpp" using namespace JoSIM; @@ -39,11 +40,9 @@ void Matrix::setup(Input& iObj) { // Create a node counter variable int64_t nodeCounter = 0; // Variables to store node configs since they are already identified here - nodeConfig.resize( - iObj.netlist.expNetlist.size(), NodeConfig::GND); + nodeConfig.resize(iObj.netlist.expNetlist.size(), NodeConfig::GND); // Only available when 4 node components are detected - nodeConfig2.resize( - iObj.netlist.expNetlist.size(), NodeConfig::GND); + nodeConfig2.resize(iObj.netlist.expNetlist.size(), NodeConfig::GND); int64_t cc = 0; for (auto& i : iObj.netlist.expNetlist) { if (i.first.at(0).at(0) != 'K') { @@ -53,18 +52,18 @@ void Matrix::setup(Input& iObj) { if (i.first.size() < 4) { // Complain if it doesnt Errors::invalid_component_errors( - ComponentErrors::INVALID_COMPONENT_DECLARATION, - Misc::vector_to_string(i.first)); + ComponentErrors::INVALID_COMPONENT_DECLARATION, + Misc::vector_to_string(i.first)); } // Create a node map that maps the node names to numbers - if (i.first.at(1).find("GND") == - std::string::npos && i.first.at(1) != "0") { + if (i.first.at(1).find("GND") == std::string::npos && + i.first.at(1) != "0") { // Add the first node to the map if not ground if (nm.count(i.first.at(1)) == 0) nm[i.first.at(1)] = nodeCounter++; nodeConfig.at(cc) = NodeConfig::POSGND; } - if (i.first.at(2).find("GND") == - std::string::npos && i.first.at(2) != "0") { + if (i.first.at(2).find("GND") == std::string::npos && + i.first.at(2) != "0") { // Add the second node to the map if not ground if (nm.count(i.first.at(2)) == 0) nm[i.first.at(2)] = nodeCounter++; if (nodeConfig.at(cc) == NodeConfig::POSGND) { @@ -75,22 +74,22 @@ void Matrix::setup(Input& iObj) { } // If the device is as 4 node device if (std::string("EFGHT").find(i.first.front().at(0)) != - std::string::npos) { + std::string::npos) { // Ensure the device has at least 6 parts if (i.first.size() < 6) { // Complain if it isnt Errors::invalid_component_errors( - ComponentErrors::INVALID_COMPONENT_DECLARATION, - Misc::vector_to_string(i.first)); + ComponentErrors::INVALID_COMPONENT_DECLARATION, + Misc::vector_to_string(i.first)); } if (i.first.at(3).find("GND") == std::string::npos && - i.first.at(3) != "0") { + i.first.at(3) != "0") { // Add the third node to the map if not ground if (nm.count(i.first.at(3)) == 0) nm[i.first.at(3)] = nodeCounter++; nodeConfig2.at(cc) = NodeConfig::POSGND; } if (i.first.at(4).find("GND") == std::string::npos && - i.first.at(4) != "0") { + i.first.at(4) != "0") { // Add the fourth node to the map if not ground if (nm.count(i.first.at(4)) == 0) nm[i.first.at(4)] = nodeCounter++; if (nodeConfig2.at(cc) == NodeConfig::POSGND) { @@ -122,7 +121,7 @@ void Matrix::create_components(Input& iObj) { } // Loop through all the components in the netlist for (auto it = iObj.netlist.expNetlist.begin(); - it != iObj.netlist.expNetlist.end(); it++) { + it != iObj.netlist.expNetlist.end(); it++) { const auto& i = *it; // If not minimal printing if (!iObj.argMin) { @@ -131,146 +130,133 @@ void Matrix::create_components(Input& iObj) { } // First character of first token indicates device type switch (i.first.front().at(0)) { - // Inductors (most common so do them first) - case 'L': - // Create an inductor and add it to the component list - components.devices.emplace_back( - Inductor( - i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); - // Store this inductor's component list index for reference - components.inductorIndices.emplace_back(components.devices.size() - 1); - break; - // Josephson junction (JJ) - case 'B': - // Create a JJ and add it to the component list - components.devices.emplace_back( - JJ(i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); - // Store this JJ's component list index for reference - components.junctionIndices.emplace_back(components.devices.size() - 1); - break; - // Resistors - case 'R': - // Create a resistor and add it to the component list - components.devices.emplace_back( - Resistor( - i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); - // Store this resistor's component list index for reference - components.resistorIndices.emplace_back(components.devices.size() - 1); - break; - // Current Source - case 'I': - // Create a current source and add it to the current sources list - components.currentsources.emplace_back( - CurrentSource(i, nodeConfig.at(cc), nm, lm, sourcegen.size())); - // Add it to the global sources list - sourcegen.emplace_back(); - sourcegen.back().parse_function( - Misc::vector_to_string(i.first), iObj, i.second); - break; - // Capacitors - case 'C': - // Create a capacitor and add it to the component list - components.devices.emplace_back( - Capacitor( - i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); - // Store this capacitor's component list index for reference - components.capacitorIndices.emplace_back(components.devices.size() - 1); - break; - // Voltage/Phase Source - case 'P': - //if(iObj.argAnal == AnalysisType::Phase) { - // Create a phase source and add it to the component list - components.devices.emplace_back( - PhaseSource( - i, nodeConfig.at(cc), nm, lm, nc, branchIndex, sourcegen.size())); - // Add it to the global sources list - sourcegen.emplace_back(); - sourcegen.back().parse_function( - Misc::vector_to_string(i.first), iObj, i.second); - // Store this phase source component list index for reference - components.psIndices.emplace_back(components.devices.size() - 1); - break; - //} else if(iObj.argAnal == AnalysisType::Voltage) { - case 'V': - // Create a voltage source and add it to the component list - components.devices.emplace_back( - VoltageSource( - i, nodeConfig.at(cc), nm, lm, nc, branchIndex, sourcegen.size())); - // Add it to the global sources list - sourcegen.emplace_back(); - sourcegen.back().parse_function( - Misc::vector_to_string(i.first), iObj, i.second); - // Store this voltage source component list index for reference - components.vsIndices.emplace_back(components.devices.size() - 1); - //} - break; - // Mutual inductance - case 'K': - // Add line to the mutual inductance list for later inspection - components.mutualinductances.emplace_back(i); - break; - // Transmission lines (4 node device) - case 'T': - // Create a transmission line and add it to the component list - components.devices.emplace_back( - TransmissionLine( - i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, - iObj.parameters, iObj.argAnal, iObj.transSim.tstep(), - branchIndex)); - if (std::get(components.devices.back()).timestepDelay_ - <= 4) { - needsTR_ = true; - return; - } - // Store the transmission line component list index for reference - components.txIndices.emplace_back(components.devices.size() - 1); - break; - // Voltage controlled current source (4 node device) - case 'G': - // Create a vccs and add it to the component list - components.devices.emplace_back( - VCCS( - i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, - iObj.parameters, branchIndex, iObj.argAnal, - iObj.transSim.tstep())); - // Store the vccs component list index for reference - components.vccsIndices.emplace_back(components.devices.size() - 1); - break; - // Current controlled current source (4 node device) - case 'F': - // Create a cccs and add it to the component list - components.devices.emplace_back( - CCCS( - i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, - iObj.parameters, branchIndex)); - // Store the cccs component list index for reference - components.cccsIndices.emplace_back(components.devices.size() - 1); - break; - // Voltage controlled voltage source (4 node device) - case 'E': - // Create a vcvs and add it to the component list - components.devices.emplace_back( - VCVS( - i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, - iObj.parameters, branchIndex)); - // Store the vcvs component list index for reference - components.vcvsIndices.emplace_back(components.devices.size() - 1); - break; - // Current controlled voltage source (4 node device) - case 'H': - // Create a ccvs and add it to the component list - components.devices.emplace_back( - CCVS( - i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, - iObj.parameters, branchIndex, iObj.argAnal, - iObj.transSim.tstep())); - // Store the ccvs component list index for reference - components.ccvsIndices.emplace_back(components.devices.size() - 1); - break; - // This is an error. This means that the component was unidentified. - default: - Errors::invalid_component_errors( - ComponentErrors::UNKNOWN_DEVICE_TYPE, i.first.front()); + // Inductors (most common so do them first) + case 'L': + // Create an inductor and add it to the component list + components.devices.emplace_back(Inductor( + i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); + // Store this inductor's component list index for reference + components.inductorIndices.emplace_back(components.devices.size() - 1); + break; + // Josephson junction (JJ) + case 'B': + // Create a JJ and add it to the component list + components.devices.emplace_back( + JJ(i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); + // Store this JJ's component list index for reference + components.junctionIndices.emplace_back(components.devices.size() - 1); + break; + // Resistors + case 'R': + // Create a resistor and add it to the component list + components.devices.emplace_back(Resistor( + i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); + // Store this resistor's component list index for reference + components.resistorIndices.emplace_back(components.devices.size() - 1); + break; + // Current Source + case 'I': + // Create a current source and add it to the current sources list + components.currentsources.emplace_back( + CurrentSource(i, nodeConfig.at(cc), nm, lm, sourcegen.size())); + // Add it to the global sources list + sourcegen.emplace_back(); + sourcegen.back().parse_function(Misc::vector_to_string(i.first), iObj, + i.second); + break; + // Capacitors + case 'C': + // Create a capacitor and add it to the component list + components.devices.emplace_back(Capacitor( + i, nodeConfig.at(cc), nm, lm, nc, iObj, spread, branchIndex)); + // Store this capacitor's component list index for reference + components.capacitorIndices.emplace_back(components.devices.size() - 1); + break; + // Voltage/Phase Source + case 'P': + // if(iObj.argAnal == AnalysisType::Phase) { + // Create a phase source and add it to the component list + components.devices.emplace_back(PhaseSource( + i, nodeConfig.at(cc), nm, lm, nc, branchIndex, sourcegen.size())); + // Add it to the global sources list + sourcegen.emplace_back(); + sourcegen.back().parse_function(Misc::vector_to_string(i.first), iObj, + i.second); + // Store this phase source component list index for reference + components.psIndices.emplace_back(components.devices.size() - 1); + break; + //} else if(iObj.argAnal == AnalysisType::Voltage) { + case 'V': + // Create a voltage source and add it to the component list + components.devices.emplace_back(VoltageSource( + i, nodeConfig.at(cc), nm, lm, nc, branchIndex, sourcegen.size())); + // Add it to the global sources list + sourcegen.emplace_back(); + sourcegen.back().parse_function(Misc::vector_to_string(i.first), iObj, + i.second); + // Store this voltage source component list index for reference + components.vsIndices.emplace_back(components.devices.size() - 1); + //} + break; + // Mutual inductance + case 'K': + // Add line to the mutual inductance list for later inspection + components.mutualinductances.emplace_back(i); + break; + // Transmission lines (4 node device) + case 'T': + // Create a transmission line and add it to the component list + components.devices.emplace_back(TransmissionLine( + i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, + iObj.parameters, iObj.argAnal, iObj.transSim.tstep(), branchIndex)); + if (std::get(components.devices.back()) + .timestepDelay_ <= 4) { + needsTR_ = true; + return; + } + // Store the transmission line component list index for reference + components.txIndices.emplace_back(components.devices.size() - 1); + break; + // Voltage controlled current source (4 node device) + case 'G': + // Create a vccs and add it to the component list + components.devices.emplace_back(VCCS( + i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, + iObj.parameters, branchIndex, iObj.argAnal, iObj.transSim.tstep())); + // Store the vccs component list index for reference + components.vccsIndices.emplace_back(components.devices.size() - 1); + break; + // Current controlled current source (4 node device) + case 'F': + // Create a cccs and add it to the component list + components.devices.emplace_back(CCCS(i, nodeConfig.at(cc), + nodeConfig2.at(cc), nm, lm, nc, + iObj.parameters, branchIndex)); + // Store the cccs component list index for reference + components.cccsIndices.emplace_back(components.devices.size() - 1); + break; + // Voltage controlled voltage source (4 node device) + case 'E': + // Create a vcvs and add it to the component list + components.devices.emplace_back(VCVS(i, nodeConfig.at(cc), + nodeConfig2.at(cc), nm, lm, nc, + iObj.parameters, branchIndex)); + // Store the vcvs component list index for reference + components.vcvsIndices.emplace_back(components.devices.size() - 1); + break; + // Current controlled voltage source (4 node device) + case 'H': + // Create a ccvs and add it to the component list + components.devices.emplace_back(CCVS( + i, nodeConfig.at(cc), nodeConfig2.at(cc), nm, lm, nc, + iObj.parameters, branchIndex, iObj.argAnal, iObj.transSim.tstep())); + // Store the ccvs component list index for reference + components.ccvsIndices.emplace_back(components.devices.size() - 1); + break; + // This is an error. This means that the component was unidentified. + default: + Errors::invalid_component_errors(ComponentErrors::UNKNOWN_DEVICE_TYPE, + i.first.front()); } // Increment the component counter ++cc; @@ -302,18 +288,19 @@ void Matrix::handle_mutual_inductance(Input& iObj) { // If the mutual inductance line has less than 4 tokens if (s.first.size() < 4) { // Complain - Errors::invalid_component_errors( - ComponentErrors::MUT_ERROR, Misc::vector_to_string(s.first)); + Errors::invalid_component_errors(ComponentErrors::MUT_ERROR, + Misc::vector_to_string(s.first)); } // Variables to store the indices of the relevant inductors int_o ind1Index, ind2Index; // Loop through all the components in the simulation for (int64_t i = 0; i < components.devices.size(); ++i) { // Find the component label - const auto& label = - std::visit([](const auto& device) noexcept -> const std::string& { - return device.netlistInfo.label_; - }, components.devices.at(i)); + const auto& label = std::visit( + [](const auto& device) noexcept -> const std::string& { + return device.netlistInfo.label_; + }, + components.devices.at(i)); // See if it matches the first inductor label of the mutual inductance if (label == s.first.at(1)) { ind1Index = i; @@ -326,12 +313,12 @@ void Matrix::handle_mutual_inductance(Input& iObj) { } // Complain if any of these inductors do not exist if (!ind1Index) { - Errors::invalid_component_errors( - ComponentErrors::MISSING_INDUCTOR, s.first.at(1)); + Errors::invalid_component_errors(ComponentErrors::MISSING_INDUCTOR, + s.first.at(1)); } if (!ind2Index) { - Errors::invalid_component_errors( - ComponentErrors::MISSING_INDUCTOR, s.first.at(2)); + Errors::invalid_component_errors(ComponentErrors::MISSING_INDUCTOR, + s.first.at(2)); } // Fetch the relevant inductors in the component list given the indices auto& ind1 = std::get(components.devices.at(ind1Index.value())); @@ -340,15 +327,13 @@ void Matrix::handle_mutual_inductance(Input& iObj) { double cf = parse_param(s.first.at(3), iObj.parameters, s.second); // Calculate the mutual inductance for this pair double mutual = - cf * std::sqrt(ind1.netlistInfo.value_ * ind2.netlistInfo.value_); + cf * std::sqrt(ind1.netlistInfo.value_ * ind2.netlistInfo.value_); if (mutual != 0) { // Add the mutual inductance to each inductor respectively - ind1.add_mutualInductance( - mutual, iObj.argAnal, iObj.transSim.tstep(), - ind2.indexInfo.currentIndex_.value()); - ind2.add_mutualInductance( - mutual, iObj.argAnal, iObj.transSim.tstep(), - ind1.indexInfo.currentIndex_.value()); + ind1.add_mutualInductance(mutual, iObj.argAnal, iObj.transSim.tstep(), + ind2.indexInfo.currentIndex_.value()); + ind2.add_mutualInductance(mutual, iObj.argAnal, iObj.transSim.tstep(), + ind1.indexInfo.currentIndex_.value()); // Add this mutual inductance to each inductor's matrix stamp ind1.set_mutualInductance(std::make_pair(ind2Index.value(), mutual)); ind2.set_mutualInductance(std::make_pair(ind1Index.value(), mutual)); @@ -403,11 +388,11 @@ void Matrix::create_nz() { // Loop through all the devices for (auto& i : components.devices) { // Get each device's non zero vector - const auto& nonZeros = - std::visit( + const auto& nonZeros = std::visit( [](const auto& device) noexcept -> const std::vector& { - return device.matrixInfo.nonZeros_; - }, i); + return device.matrixInfo.nonZeros_; + }, + i); // Insert the non zero vector of the device into the greater vector nz.insert(nz.end(), nonZeros.begin(), nonZeros.end()); } @@ -424,13 +409,18 @@ void Matrix::create_ci() { ci.emplace_back(ti.second); } } + int sum = 0; + for (auto& i : ci) { + sum += i; + } // Loop through all the devices for (auto& i : components.devices) { // Get each device's column index vector - const auto& columnIndices = - std::visit([](const auto& device) noexcept -> const std::vector& { - return device.matrixInfo.columnIndex_; - }, i); + const auto& columnIndices = std::visit( + [](const auto& device) noexcept -> const std::vector& { + return device.matrixInfo.columnIndex_; + }, + i); // Insert the column index vector of the device into the greater vector ci.insert(ci.end(), columnIndices.begin(), columnIndices.end()); } @@ -448,10 +438,11 @@ void Matrix::create_rp() { // Loop through all the devices for (auto& i : components.devices) { // Get the row pointer vector for each device - const auto& rowPointer = - std::visit([](const auto& device) noexcept -> const std::vector& { - return device.matrixInfo.rowPointer_; - }, i); + const auto& rowPointer = std::visit( + [](const auto& device) noexcept -> const std::vector& { + return device.matrixInfo.rowPointer_; + }, + i); // For each entry in the row pointer vector of the device for (const auto& ti : rowPointer) { // Add it to the last entry of the greater row pointer vector diff --git a/src/Misc.cpp b/src/Misc.cpp index 041cf860..8ebf2a41 100644 --- a/src/Misc.cpp +++ b/src/Misc.cpp @@ -2,31 +2,41 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Misc.hpp" -#include "JoSIM/Constants.hpp" #include -#include -#include #include -#include #include +#include +#include +#include + +#include "JoSIM/Constants.hpp" using namespace JoSIM; double Misc::string_constant(const std::string& s) { - if (s == "PI") return Constants::PI; - else if (s == "PHI_ZERO") return Constants::PHI_ZERO; - else if (s == "BOLTZMANN") return Constants::BOLTZMANN; - else if (s == "EV") return Constants::EV; - else if (s == "HBAR") return Constants::HBAR; - else if (s == "C") return Constants::C; - else if (s == "MU0") return Constants::MU0; - else if (s == "EPS0") return Constants::EPS0; - else if (s == "SIGMA") return Constants::SIGMA; + if (s == "PI") + return Constants::PI; + else if (s == "PHI_ZERO") + return Constants::PHI_ZERO; + else if (s == "BOLTZMANN") + return Constants::BOLTZMANN; + else if (s == "EV") + return Constants::EV; + else if (s == "HBAR") + return Constants::HBAR; + else if (s == "C") + return Constants::C; + else if (s == "MU0") + return Constants::MU0; + else if (s == "EPS0") + return Constants::EPS0; + else if (s == "SIGMA") + return Constants::SIGMA; return 0.0; } -bool Misc::isclose(const double &a, const double &b) { +bool Misc::isclose(const double& a, const double& b) { return fabs(a - b) < DBL_EPSILON; } @@ -39,10 +49,9 @@ std::string Misc::file_from_path(const std::string& path) { return path.substr(posLastSlash + 1); } -bool Misc::has_suffix(const std::string& str, - const std::string& suffix) { +bool Misc::has_suffix(const std::string& str, const std::string& suffix) { return str.size() >= suffix.size() && - str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } bool Misc::starts_with(const std::string& input, char test) { @@ -62,9 +71,8 @@ std::string Misc::vector_to_string(const tokens_t& s, std::string d) { return ss.str(); } -tokens_t Misc::tokenize( - const std::string& c, std::string d, bool trimEmpty, bool trimSpaces, - int64_t count) { +tokens_t Misc::tokenize(const std::string& c, std::string d, bool trimEmpty, + bool trimSpaces, int64_t count) { // Create a position token to point to the found delimiter size_t pos = 0, lastPos = 0; // Tokens to return @@ -98,8 +106,8 @@ tokens_t Misc::tokenize( if (trimSpaces) { if (!tokens.empty()) { // Remove trailing, leading and duplicate spaces between tokens - tokens.back() = - std::regex_replace(tokens.back(), std::regex("^ +| +$|( ) +"), "$1"); + tokens.back() = std::regex_replace(tokens.back(), + std::regex("^ +| +$|( ) +"), "$1"); } } lastPos = pos + 1; @@ -121,7 +129,7 @@ tokens_t Misc::tokenize( if (trimSpaces) { // Remove trailing, leading and duplicate spaces between tokens tokens.back() = - std::regex_replace(tokens.back(), std::regex("^ +| +$|( ) +"), "$1"); + std::regex_replace(tokens.back(), std::regex("^ +| +$|( ) +"), "$1"); } // Return the tokens return tokens; @@ -129,14 +137,15 @@ tokens_t Misc::tokenize( void Misc::ltrim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int64_t ch) { - return !std::isspace(ch); - })); + return !std::isspace(ch); + })); } void Misc::rtrim(std::string& s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](int64_t ch) { - return !std::isspace(ch); - }).base(), s.end()); + s.erase(std::find_if(s.rbegin(), s.rend(), + [](int64_t ch) { return !std::isspace(ch); }) + .base(), + s.end()); } double Misc::modifier(const std::string& value) { @@ -150,60 +159,59 @@ double Misc::modifier(const std::string& value) { Errors::misc_errors(MiscErrors::STOD_ERROR, value); } switch (value.substr(sz)[0]) { - /* mega */ - case 'X': - return number * 1E6; - /* mega or milli */ - case 'M': - /* mega */ - if (value.substr(sz)[1] == 'E' && value.substr(sz)[2] == 'G') + /* mega */ + case 'X': return number * 1E6; - /* milli */ - else - return number * 1E-3; - /* micro */ - case 'U': - return number * 1E-6; - /* nano */ - case 'N': - return number * 1E-9; - /* pico */ - case 'P': - return number * 1E-12; - /* femto */ - case 'F': - return number * 1E-15; - /* kilo */ - case 'K': - return number * 1E3; - /* giga */ - case 'G': - return number * 1E9; - /* tera */ - case 'T': - return number * 1E12; - /* auto modifier */ - case 'E': - return std::stod(value); - default: - return number; + /* mega or milli */ + case 'M': + /* mega */ + if (value.substr(sz)[1] == 'E' && value.substr(sz)[2] == 'G') + return number * 1E6; + /* milli */ + else + return number * 1E-3; + /* micro */ + case 'U': + return number * 1E-6; + /* nano */ + case 'N': + return number * 1E-9; + /* pico */ + case 'P': + return number * 1E-12; + /* femto */ + case 'F': + return number * 1E-15; + /* kilo */ + case 'K': + return number * 1E3; + /* giga */ + case 'G': + return number * 1E9; + /* tera */ + case 'T': + return number * 1E12; + /* auto modifier */ + case 'E': + return std::stod(value); + default: + return number; } } void Misc::unique_push(std::vector& vector, - const std::string& string) { + const std::string& string) { if (std::find(vector.begin(), vector.end(), string) == vector.end()) { vector.push_back(string); } } int64_t Misc::index_of(const std::vector& vector, - const std::string& value) { + const std::string& value) { int64_t counter = 0; for (const auto& i : vector) { /* Value found, return counter */ - if (value == vector.at(counter)) - return counter; + if (value == vector.at(counter)) return counter; counter++; } /* Value was not found, set counter equal to -1 and return */ @@ -212,7 +220,7 @@ int64_t Misc::index_of(const std::vector& vector, } std::string Misc::substring_after(const std::string& str, - const std::string& whatpart) { + const std::string& whatpart) { std::size_t pos = 0; std::string substring; if (str.find(whatpart) != std::string::npos) @@ -222,7 +230,7 @@ std::string Misc::substring_after(const std::string& str, } std::string Misc::substring_before(const std::string& str, - const std::string& whatpart) { + const std::string& whatpart) { std::string substring; if (str.find(whatpart) != std::string::npos) { std::size_t pos = str.find(whatpart); @@ -232,9 +240,8 @@ std::string Misc::substring_before(const std::string& str, return str; } -bool Misc::findX(const std::vector& segment, - std::string& theLine, - int64_t& linePos) { +bool Misc::findX(const std::vector& segment, std::string& theLine, + int64_t& linePos) { for (int64_t i = linePos; i < segment.size(); ++i) { if (segment.at(i).at(0) == 'X') { theLine = segment.at(i); @@ -250,8 +257,7 @@ bool Misc::findX(const std::vector& segment, int64_t Misc::numDigits(int64_t number) { int64_t digits = 0; - if (number <= 0) - digits = 1; + if (number <= 0) digits = 1; while (number) { number /= 10; digits++; @@ -262,10 +268,9 @@ int64_t Misc::numDigits(int64_t number) { double Misc::grand() { double r, u1, u2, lt; double scale = 1.0 / 1024.0 / 1024.0 / 1024.0 / 2.0; - u1 = (static_cast(rand()) + 1) / - (static_cast(RAND_MAX) + 1); + u1 = (static_cast(rand()) + 1) / (static_cast(RAND_MAX) + 1); u2 = static_cast(rand()) * 2 * Constants::PI / - static_cast(RAND_MAX); + static_cast(RAND_MAX); lt = sqrt(-2.0 * log(u1)); r = cos(u2) * lt; return r; diff --git a/src/Model.cpp b/src/Model.cpp index 4cb17720..4dee8312 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -2,19 +2,20 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Model.hpp" + #include "JoSIM/Errors.hpp" #include "JoSIM/Misc.hpp" #include "JoSIM/TypeDefines.hpp" using namespace JoSIM; -void Model::parse_model( - const std::pair& s, - vector_pair_t& models, const param_map& p) { +void Model::parse_model(const std::pair& s, + vector_pair_t& models, + const param_map& p) { // Ensure the model conforms to correct syntax if (s.first.size() < 3) { - Errors::model_errors( - ModelErrors::BAD_MODEL_DEFINITION, Misc::vector_to_string(s.first)); + Errors::model_errors(ModelErrors::BAD_MODEL_DEFINITION, + Misc::vector_to_string(s.first)); } // Create a model that will be stored Model temp; @@ -22,17 +23,16 @@ void Model::parse_model( temp.modelName(s.first.at(1)); // The third token needs to start with "JJ" for this to be valid if (s.first.at(2).compare(0, 2, "JJ") != 0) { - Errors::model_errors( - ModelErrors::UNKNOWN_MODEL_TYPE, Misc::vector_to_string(s.first)); + Errors::model_errors(ModelErrors::UNKNOWN_MODEL_TYPE, + Misc::vector_to_string(s.first)); } // Create a temporary tokens variable containing the model parameters tokens_t tokens(s.first.begin() + 2, s.first.end()); - tokens = Misc::tokenize( - Misc::vector_to_string(tokens).substr(2), "=(), "); + tokens = Misc::tokenize(Misc::vector_to_string(tokens).substr(2), "=(), "); // Sanity check, there should be an even number of tokens (parameter=value) if (tokens.size() % 2 != 0) { - Errors::model_errors( - ModelErrors::BAD_MODEL_DEFINITION, Misc::vector_to_string(s.first)); + Errors::model_errors(ModelErrors::BAD_MODEL_DEFINITION, + Misc::vector_to_string(s.first)); } double value = 0.0; // Loop through the parameter tokens @@ -40,8 +40,8 @@ void Model::parse_model( // Every even odd token should be a value (otherwise complain) value = parse_param(tokens.at(i + 1), p, s.second); if (std::isnan(value)) { - Errors::model_errors( - ModelErrors::BAD_MODEL_DEFINITION, Misc::vector_to_string(s.first)); + Errors::model_errors(ModelErrors::BAD_MODEL_DEFINITION, + Misc::vector_to_string(s.first)); } // Assign the relevant model parameters if (tokens.at(i) == "VG" || tokens.at(i) == "VGAP") { @@ -71,12 +71,14 @@ void Model::parse_model( temp.icFct(value); } else if (tokens.at(i) == "PHI") { temp.phiOff(value); + } else if (tokens.at(i) == "CPR") { + temp.cpr(value); } else { // Incompatible parameter - Errors::model_errors(ModelErrors::PARAM_TYPE_ERROR, - Misc::vector_to_string( - tokens_t{ Misc::vector_to_string(s.first), - "\nThe parameter: ", tokens.at(i) })); + Errors::model_errors( + ModelErrors::PARAM_TYPE_ERROR, + Misc::vector_to_string(tokens_t{Misc::vector_to_string(s.first), + "\nThe parameter: ", tokens.at(i)})); } } diff --git a/src/Netlist.cpp b/src/Netlist.cpp index 9e9dd935..acf3eb48 100644 --- a/src/Netlist.cpp +++ b/src/Netlist.cpp @@ -2,20 +2,21 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Netlist.hpp" + +#include + #include "JoSIM/AnalysisType.hpp" #include "JoSIM/Errors.hpp" #include "JoSIM/Misc.hpp" #include "JoSIM/ProgressBar.hpp" -#include - using namespace JoSIM; void Netlist::id_io_subc_label( - const tokens_t& lineTokens, tokens_t& io, s_map& params, - std::string& subcktName, std::string& label, - const std::unordered_map& subcircuits) { - // Id the label + const tokens_t& lineTokens, tokens_t& io, s_map& params, + std::string& subcktName, std::string& label, + const std::unordered_map& subcircuits) { + // Id the label label = lineTokens.front(); // Found flag bool found = false; @@ -36,14 +37,14 @@ void Netlist::id_io_subc_label( } } if (!found) { - Errors::input_errors( - InputErrors::UNKNOWN_SUBCKT, Misc::vector_to_string(lineTokens)); + Errors::input_errors(InputErrors::UNKNOWN_SUBCKT, + Misc::vector_to_string(lineTokens)); } } -bool Netlist::rename_io_nodes( - std::string& node, const tokens_t& subIO, const tokens_t& parentIO) { - // If the subcircuit IO contains the first node +bool Netlist::rename_io_nodes(std::string& node, const tokens_t& subIO, + const tokens_t& parentIO) { + // If the subcircuit IO contains the first node if (std::count(subIO.begin(), subIO.end(), node) != 0) { // Loop through the subcircuit IO for (int64_t l = 0; l < subIO.size(); ++l) { @@ -60,8 +61,8 @@ bool Netlist::rename_io_nodes( return false; } -void Netlist::expand_io(Subcircuit& subc, s_map& params, const tokens_t& io, - const std::string& label) { +void Netlist::expand_io(Subcircuit& subc, s_map& params, const tokens_t& io, + const std::string& label) { // Sanity check if (io.size() != subc.io.size()) { Errors::input_errors(InputErrors::IO_MISMATCH, label); @@ -169,8 +170,8 @@ void Netlist::expand_subcircuits() { // Variable to store io and parameters tokens_t io; s_map params; - id_io_subc_label( - subcCurrentLine, io, params, subcktName, label, subcircuits); + id_io_subc_label(subcCurrentLine, io, params, subcktName, label, + subcircuits); // Create a copy of the subircuit for this instance Subcircuit subc = subcircuits.at(subcktName); // If not nested @@ -181,7 +182,7 @@ void Netlist::expand_subcircuits() { subcircuit.lines.erase(subcircuit.lines.begin() + j); // Insert the subcircuit token lines at the erased line position subcircuit.lines.insert(subcircuit.lines.begin() + j, - subc.lines.begin(), subc.lines.end()); + subc.lines.begin(), subc.lines.end()); // Reduce the total amound of subcircuits in this subcircuit by 1 --subcircuit.subcktCounter; ++cc; @@ -227,16 +228,15 @@ void Netlist::expand_maindesign() { // Variable to store io and parameters tokens_t io; s_map params; - id_io_subc_label(maindesign.at(i), io, params, - subcktName, label, subcircuits); + id_io_subc_label(maindesign.at(i), io, params, subcktName, label, + subcircuits); // Copy of subcircuit for this instance Subcircuit subc = subcircuits.at(subcktName); // Expand the appropriate IO nodes of the subcircuit for this instance expand_io(subc, params, io, label); // Add the expanded subcircuit lines to the expanded netlist - expNetlist.insert(expNetlist.end(), subc.lines.begin(), - subc.lines.end()); - // If the line is not a subcircuit + expNetlist.insert(expNetlist.end(), subc.lines.begin(), subc.lines.end()); + // If the line is not a subcircuit } else { // Add the line tokens to the expanded netlist expNetlist.push_back(std::make_pair(maindesign.at(i), std::nullopt)); diff --git a/src/Noise.cpp b/src/Noise.cpp index 7732c595..7ce5d1b9 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -2,10 +2,11 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Noise.hpp" + #include "JoSIM/Constants.hpp" -#include "JoSIM/Parameters.hpp" -#include "JoSIM/Misc.hpp" #include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/Parameters.hpp" using namespace JoSIM; @@ -26,7 +27,7 @@ void JoSIM::Noise::determine_noise_effective_bandwidth(Input& iObj) { } double JoSIM::Noise::determine_spectral_amplitude(const double& R, - const double& T) { + const double& T) { // spectral amplitute = sqrt(4 * kB * T / R) double spAmp = sqrt((4 * Constants::BOLTZMANN * T) / R); return spAmp; diff --git a/src/Output.cpp b/src/Output.cpp index 206afe3e..7a9c106f 100644 --- a/src/Output.cpp +++ b/src/Output.cpp @@ -2,21 +2,22 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Output.hpp" -#include "JoSIM/AnalysisType.hpp" -#include "JoSIM/FileOutputType.hpp" -#include "JoSIM/Input.hpp" -#include "JoSIM/Simulation.hpp" -#include "JoSIM/Constants.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/ProgressBar.hpp" #include #include -#include -#include +#include #include +#include #include -#include +#include + +#include "JoSIM/AnalysisType.hpp" +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/FileOutputType.hpp" +#include "JoSIM/Input.hpp" +#include "JoSIM/ProgressBar.hpp" +#include "JoSIM/Simulation.hpp" using namespace JoSIM; @@ -26,27 +27,21 @@ Output::Output(Input& iObj, Matrix& mObj, Simulation& sObj) { // Format the output into the relevant type if (iObj.cli_output_file) { if (iObj.cli_output_file.value().type() == FileOutputType::Csv) { - format_csv_or_dat( - iObj.cli_output_file.value().name(), ',', iObj.argMin); + format_csv_or_dat(iObj.cli_output_file.value().name(), ',', iObj.argMin); } else if (iObj.cli_output_file.value().type() == FileOutputType::Dat) { - format_csv_or_dat( - iObj.cli_output_file.value().name(), ' ', iObj.argMin); + format_csv_or_dat(iObj.cli_output_file.value().name(), ' ', iObj.argMin); } else if (iObj.cli_output_file.value().type() == FileOutputType::Raw) { - format_raw( - iObj.cli_output_file.value().name(), iObj.argMin); + format_raw(iObj.cli_output_file.value().name(), iObj.argMin); } } if (!iObj.output_files.empty()) { for (int64_t i = 0; i < iObj.output_files.size(); ++i) { if (iObj.output_files.at(i).type() == FileOutputType::Csv) { - format_csv_or_dat( - iObj.output_files.at(i).name(), ',', iObj.argMin, i); + format_csv_or_dat(iObj.output_files.at(i).name(), ',', iObj.argMin, i); } else if (iObj.output_files.at(i).type() == FileOutputType::Dat) { - format_csv_or_dat( - iObj.output_files.at(i).name(), ' ', iObj.argMin, i); + format_csv_or_dat(iObj.output_files.at(i).name(), ' ', iObj.argMin, i); } else if (iObj.output_files.at(i).type() == FileOutputType::Raw) { - format_raw( - iObj.output_files.at(i).name(), iObj.argMin, i); + format_raw(iObj.output_files.at(i).name(), iObj.argMin, i); } } } @@ -55,8 +50,7 @@ Output::Output(Input& iObj, Matrix& mObj, Simulation& sObj) { } } -void Output::write_output( - const Input& iObj, Matrix& mObj, Simulation& sObj) { +void Output::write_output(const Input& iObj, Matrix& mObj, Simulation& sObj) { // Shorthand auto& x = sObj.results.xVector; auto& t = sObj.results.timeAxis; @@ -64,23 +58,23 @@ void Output::write_output( // Indices to print std::vector result_indices; for (auto i = 0; i < t.size(); ++i) { - if (t.at(i) >= tran.prstart()) { - result_indices.emplace_back(i); - break; - } + if (t.at(i) >= tran.prstart()) { + result_indices.emplace_back(i); + break; + } } double next_print_point = tran.prstart() + tran.prstep(); for (auto i = result_indices.back(); i < t.size(); ++i) { - if (t.at(i) >= next_print_point) { - result_indices.emplace_back(i); - next_print_point += tran.prstep(); - } + if (t.at(i) >= next_print_point) { + result_indices.emplace_back(i); + next_print_point += tran.prstep(); + } } // Create the time trace traces.emplace_back("time"); traces.back().type_ = 'T'; for (auto i : result_indices) { - traces.back().data_.emplace_back(t.at(i)); + traces.back().data_.emplace_back(t.at(i)); } // Print only the indices of the relevant traces int64_t cc = 0; @@ -134,7 +128,7 @@ void Output::write_output( } else { valin1n2 = valin1n1 = valin1; valin2n2 = valin2n1 = valin2; - } + } // If the analysis method was voltage if (iObj.argAnal == AnalysisType::Voltage) { value = valin1 - valin2; @@ -143,9 +137,10 @@ void Output::write_output( if (i.deviceLabel.value().at(3) == 'B' && vi != -1) { value = valvi; } else { - value = ((3.0 * Constants::SIGMA) / (2.0 * iObj.transSim.tstep())) - * ((valin1 - valin2) - (4.0 / 3.0) * (valin1n1 - valin2n1) - + (1.0 / 3.0) * (valin1n2 - valin2n2)); + value = + ((3.0 * Constants::SIGMA) / (2.0 * iObj.transSim.tstep())) * + ((valin1 - valin2) - (4.0 / 3.0) * (valin1n1 - valin2n1) + + (1.0 / 3.0) * (valin1n2 - valin2n2)); valin1n2 = valin1n1; valin1n1 = valin1; valin2n2 = valin2n1; @@ -176,10 +171,10 @@ void Output::write_output( if (i.deviceLabel.value().at(3) == 'B' && vi != -1) { value = valvi; } else { - value = ((2.0 * iObj.transSim.tstep()) / - (3.0 * Constants::SIGMA)) * (valin1 - valin2) - + (4.0 / 3.0) * (phaseN1) - - (1.0 / 3.0) * (phaseN2); + value = + ((2.0 * iObj.transSim.tstep()) / (3.0 * Constants::SIGMA)) * + (valin1 - valin2) + + (4.0 / 3.0) * (phaseN1) - (1.0 / 3.0) * (phaseN2); phaseN2 = phaseN1; phaseN1 = value; } @@ -198,8 +193,8 @@ void Output::write_output( } } else { for (auto j : result_indices) { - double value = mObj.sourcegen.at(i.sourceIndex.value()).value( - sObj.results.timeAxis.at(j)); + double value = mObj.sourcegen.at(i.sourceIndex.value()) + .value(sObj.results.timeAxis.at(j)); traces.back().type_ = 'I'; traces.back().data_.emplace_back(value); } @@ -246,10 +241,10 @@ void Output::write_output( } } -void Output::format_csv_or_dat( - const std::string& filename, const char& delimiter, bool argmin, - int64_t fIndex) { - std::vector tIndices = { 0 }; +void Output::format_csv_or_dat(const std::string& filename, + const char& delimiter, bool argmin, + int64_t fIndex) { + std::vector tIndices = {0}; for (int64_t i = 1; i < traces.size(); ++i) { if (traces.at(i).fileIndex == fIndex || fIndex == -1) { tIndices.emplace_back(i); @@ -259,7 +254,7 @@ void Output::format_csv_or_dat( outfile << std::setprecision(15); if (outfile.is_open()) { for (int64_t i = 0; i < tIndices.size() - 1; ++i) { - outfile << traces.at(tIndices.at(i)).name_ << delimiter; + outfile << traces.at(tIndices.at(i)).name_ << delimiter; } outfile << traces.at(tIndices.at(tIndices.size() - 1)).name_ << "\n"; ProgressBar bar; @@ -276,11 +271,12 @@ void Output::format_csv_or_dat( bar.update(j); } for (int64_t i = 0; i < tIndices.size() - 1; ++i) { - outfile << std::scientific << std::setprecision(6) << - traces.at(tIndices.at(i)).data_.at(j) << delimiter; + outfile << std::scientific << std::setprecision(6) + << traces.at(tIndices.at(i)).data_.at(j) << delimiter; } - outfile << std::scientific << std::setprecision(6) << - traces.at(tIndices.at(tIndices.size() - 1)).data_.at(j) << "\n"; + outfile << std::scientific << std::setprecision(6) + << traces.at(tIndices.at(tIndices.size() - 1)).data_.at(j) + << "\n"; } if (!argmin) { bar.complete(); @@ -292,8 +288,9 @@ void Output::format_csv_or_dat( } // Writes the output to a standard spice raw file -void Output::format_raw(const std::string& filename, bool argmin, int64_t fIndex) { - std::vector tIndices = { 0 }; +void Output::format_raw(const std::string& filename, bool argmin, + int64_t fIndex) { + std::vector tIndices = {0}; for (int64_t i = 1; i < traces.size(); ++i) { if (traces.at(i).fileIndex == fIndex || fIndex == -1) { tIndices.emplace_back(i); @@ -359,12 +356,12 @@ void Output::format_raw(const std::string& filename, bool argmin, int64_t fIndex bar.update(i); } // Point and time value - outfile << std::left << std::setw(pointSizeSpacing) << i << - traces.at(0).data_.at(i) << "\n"; + outfile << std::left << std::setw(pointSizeSpacing) << i + << traces.at(0).data_.at(i) << "\n"; // Fill in rest of variable values for (int64_t j = 1; j < tIndices.size(); ++j) { - outfile << std::left << std::setw(pointSizeSpacing) << "" << - traces.at(tIndices.at(j)).data_.at(i) << "\n"; + outfile << std::left << std::setw(pointSizeSpacing) << "" + << traces.at(tIndices.at(j)).data_.at(i) << "\n"; } } if (!argmin) { @@ -393,10 +390,10 @@ void Output::format_cout(const bool& argMin) { for (int64_t j = 0; j < traces.at(0).data_.size(); ++j) { for (int64_t i = 0; i < traces.size() - 1; ++i) { std::cout << std::setw(15) << std::scientific << std::setprecision(6) - << traces.at(i).data_.at(j) << " "; + << traces.at(i).data_.at(j) << " "; } - std::cout << std::setw(15) << std::scientific << std::setprecision(6) << - traces.at(traces.size() - 1).data_.at(j) << "\n"; + std::cout << std::setw(15) << std::scientific << std::setprecision(6) + << traces.at(traces.size() - 1).data_.at(j) << "\n"; } } } \ No newline at end of file diff --git a/src/Parameters.cpp b/src/Parameters.cpp index f7216cb9..bc33887e 100644 --- a/src/Parameters.cpp +++ b/src/Parameters.cpp @@ -2,543 +2,519 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Parameters.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Constants.hpp" -#include "JoSIM/Errors.hpp" +#include #include #include -#include + +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" using namespace JoSIM; -void JoSIM::create_parameter( - const tokens_t& s, param_map& parameters, string_o subc) { - // Temporary parameter which will be stored - Parameter temp; - // Check to ensure declaration is valid - if (s.size() < 2) { - Errors::parsing_errors( - ParsingErrors::INVALID_DECLARATION, Misc::vector_to_string(s)); - } - // Check to see if '=' exists - if (Misc::vector_to_string(s).find('=') == std::string::npos) { - Errors::parsing_errors( - ParsingErrors::INVALID_DECLARATION, Misc::vector_to_string(s)); - } - // Split the line/tokens int64_to the parameter name and expression - tokens_t tokens(s.begin() + 1, s.end()); - // 1st token is parameter name, 2nd is the expression - tokens = Misc::tokenize( - Misc::vector_to_string(tokens, ""), "=", true, true); - // Set the expresion for the temporary parameter - temp.set_expression(tokens.at(1)); - // Warn user that duplicate parameter exists, this overwrites previous - if (parameters.count(ParameterName(tokens.at(0), subc)) != 0) { - Errors::parsing_errors( - ParsingErrors::EXPRESSION_ARLEADY_DEFINED, Misc::vector_to_string(s)); - } - // Insert the parameter int64_to a map of known parameters for parsing - parameters.insert({ ParameterName(tokens.at(0), subc), temp }); +void JoSIM::create_parameter(const tokens_t& s, param_map& parameters, + string_o subc) { + // Temporary parameter which will be stored + Parameter temp; + // Check to ensure declaration is valid + if (s.size() < 2) { + Errors::parsing_errors(ParsingErrors::INVALID_DECLARATION, + Misc::vector_to_string(s)); + } + // Check to see if '=' exists + if (Misc::vector_to_string(s).find('=') == std::string::npos) { + Errors::parsing_errors(ParsingErrors::INVALID_DECLARATION, + Misc::vector_to_string(s)); + } + // Split the line/tokens int64_to the parameter name and expression + tokens_t tokens(s.begin() + 1, s.end()); + // 1st token is parameter name, 2nd is the expression + tokens = Misc::tokenize(Misc::vector_to_string(tokens, ""), "=", true, true); + // Set the expresion for the temporary parameter + temp.set_expression(tokens.at(1)); + // Warn user that duplicate parameter exists, this overwrites previous + if (parameters.count(ParameterName(tokens.at(0), subc)) != 0) { + Errors::parsing_errors(ParsingErrors::EXPRESSION_ARLEADY_DEFINED, + Misc::vector_to_string(s)); + } + // Insert the parameter int64_to a map of known parameters for parsing + parameters.insert({ParameterName(tokens.at(0), subc), temp}); } // Possible functions that can be called const std::vector funcs = { "COS", "SIN", "TAN", "ACOS", "ASIN", "ATAN", "COSH", "SINH", "TANH", - "ACOSH", "ASINH", "ATANH", "EXP", "LOG", "LOG10", "SQRT", "CBRT" -}; + "ACOSH", "ASINH", "ATANH", "EXP", "LOG", "LOG10", "SQRT", "CBRT"}; int64_t JoSIM::precedence_lvl(const std::string& op) { - switch (op.at(0)) { - // + and - are lowest level + switch (op.at(0)) { + // + and - are lowest level case '+': case '-': - return 1; - // * and / are higher level + return 1; + // * and / are higher level case '*': case '/': - return 2; - // ^ (pow) is highest level + return 2; + // ^ (pow) is highest level case '^': - return 3; - // default (functions) are max level + return 3; + // default (functions) are max level default: - return 4; - } - return 4; + return 4; + } + return 4; } -double JoSIM::parse_param( - const std::string& expr, const param_map& params, string_o subc, - bool single) { - // Initialize the expression to evaluate - std::string expToEval = expr; - // Sanity check, prepend 0 to a string where the value is eg. .5 to vorm 0.5 - if (expToEval.front() == '.') { - expToEval = "0" + expToEval; - } - // Remove any and all whitespace characters - expToEval.erase(std::remove_if(expToEval.begin(), expToEval.end(), isspace), - expToEval.end()); - // Stacks used in the shunting yard - std::vector rpnQueue, rpnQueueCopy, opStack; - // Create two copies of the type each element in the queue is - std::vector qType, qTypeCopy; - // Substring reference to part of the expression - std::string partToEval; - // Counter - int64_t popCount = 0; - // Variable for the result to be returned - double result; - // Evaluate expression piece by piece until it is empy - while (!expToEval.empty()) { - // First test the expression to see if it is a parameter - if (params.count(ParameterName(expToEval, subc)) != 0) { - if (!params.at(ParameterName(expToEval, subc)).get_value()) { - if (!single) { - // Return NaN to indicate this ocurred - return std::numeric_limits::quiet_NaN(); - } - else { - Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, expr); - } - } - } - // Find the position of the first operator - int64_t opLoc = expToEval.find_first_of("/*-+(){}[]^"); - // If no operator is found - if (opLoc == -1) { - // The part to evaluate is the entire experssion - partToEval = expToEval; - // If an operator is found +double JoSIM::parse_param(const std::string& expr, const param_map& params, + string_o subc, bool single) { + // Initialize the expression to evaluate + std::string expToEval = expr; + // Sanity check, prepend 0 to a string where the value is eg. .5 to vorm 0.5 + if (expToEval.front() == '.') { + expToEval = "0" + expToEval; + } + // Remove any and all whitespace characters + expToEval.erase(std::remove_if(expToEval.begin(), expToEval.end(), isspace), + expToEval.end()); + // Stacks used in the shunting yard + std::vector rpnQueue, rpnQueueCopy, opStack; + // Create two copies of the type each element in the queue is + std::vector qType, qTypeCopy; + // Substring reference to part of the expression + std::string partToEval; + // Counter + int64_t popCount = 0; + // Variable for the result to be returned + double result; + // Evaluate expression piece by piece until it is empy + while (!expToEval.empty()) { + // First test the expression to see if it is a parameter + if (params.count(ParameterName(expToEval, subc)) != 0) { + if (!params.at(ParameterName(expToEval, subc)).get_value()) { + if (!single) { + // Return NaN to indicate this ocurred + return std::numeric_limits::quiet_NaN(); + } else { + Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, expr); } - else { - // If the operator is either a '-' or a '+' - if (expToEval.at(opLoc) == '-' || expToEval.at(opLoc) == '+') { - // If this operator is not the start of the string - if (opLoc != 0) { - // Do a few checks - bool digitBeforeE = false; - bool eBefore = false; - bool digitAfter = false; - // If the character preceeding this operator is an E - if (expToEval[opLoc - 1] == 'E') eBefore = true; - // If the character after the operator is a digit - if (opLoc != expToEval.length() - 1) { - if (std::isdigit(expToEval[opLoc + 1])) digitAfter = true; - } - // If the char before E is a digit - if ((opLoc - 1) != 0) { - if (std::isdigit(expToEval[opLoc - 2])) digitBeforeE = true; - } - if (eBefore && digitAfter && digitBeforeE) { - // Find the next operator since this operator is not an operator - opLoc = expToEval.find_first_of("/*-+(){}[]^", opLoc + 1); - } + } + } + // Find the position of the first operator + int64_t opLoc = expToEval.find_first_of("/*-+(){}[]^"); + // If no operator is found + if (opLoc == -1) { + // The part to evaluate is the entire experssion + partToEval = expToEval; + // If an operator is found + } else { + // If the operator is either a '-' or a '+' + if (expToEval.at(opLoc) == '-' || expToEval.at(opLoc) == '+') { + // If this operator is not the start of the string + if (opLoc != 0) { + // Do a few checks + bool digitBeforeE = false; + bool eBefore = false; + bool digitAfter = false; + // If the character preceeding this operator is an E + if (expToEval[opLoc - 1] == 'E') eBefore = true; + // If the character after the operator is a digit + if (opLoc != expToEval.length() - 1) { + if (std::isdigit(expToEval[opLoc + 1])) digitAfter = true; + } + // If the char before E is a digit + if ((opLoc - 1) != 0) { + if (std::isdigit(expToEval[opLoc - 2])) digitBeforeE = true; + } + if (eBefore && digitAfter && digitBeforeE) { + // Find the next operator since this operator is not an operator + opLoc = expToEval.find_first_of("/*-+(){}[]^", opLoc + 1); + } + } else { + // If the character after the operator is a digit but not before + if ((opLoc != expToEval.length() - 1) && !qType.empty()) { + if (qType.back() != 'V') { + if (std::isdigit(expToEval[opLoc + 1])) { + // Find next operator since this operator is not an operator + opLoc = expToEval.find_first_of("/*-+(){}[]^", opLoc + 1); + // Do a few checks + bool digitBeforeE = false; + bool eBefore = false; + bool digitAfter = false; + // If the character preceeding this operator is an E + if (expToEval[opLoc - 1] == 'E') eBefore = true; + // If the character after the operator is a digit + if (opLoc != expToEval.length() - 1) { + if (std::isdigit(expToEval[opLoc + 1])) digitAfter = true; } - else { - // If the character after the operator is a digit but not before - if ((opLoc != expToEval.length() - 1) && !qType.empty()) { - if (qType.back() != 'V') { - if (std::isdigit(expToEval[opLoc + 1])) { - // Find next operator since this operator is not an operator - opLoc = expToEval.find_first_of("/*-+(){}[]^", opLoc + 1); - // Do a few checks - bool digitBeforeE = false; - bool eBefore = false; - bool digitAfter = false; - // If the character preceeding this operator is an E - if (expToEval[opLoc - 1] == 'E') eBefore = true; - // If the character after the operator is a digit - if (opLoc != expToEval.length() - 1) { - if (std::isdigit(expToEval[opLoc + 1])) digitAfter = true; - } - // If the char before E is a digit - if ((opLoc - 1) != 0) { - if (std::isdigit(expToEval[opLoc - 2])) digitBeforeE = true; - } - if (eBefore && digitAfter && digitBeforeE) { - // Find next operator since this operator is not an operator - opLoc = expToEval.find_first_of("/*-+(){}[]^", opLoc + 1); - } - } - } - } + // If the char before E is a digit + if ((opLoc - 1) != 0) { + if (std::isdigit(expToEval[opLoc - 2])) digitBeforeE = true; } - } - // If the operator is at the start of the string - if (opLoc == 0) { - // The part to evaluate is the the operator - partToEval = expToEval.substr(0, opLoc + 1); - // If the operator is further along - } - else { - // The part to evaluate is from the start to the the operator - partToEval = expToEval.substr(0, opLoc); - } - } - // Handle a numerical value - if (isdigit(partToEval.at(0)) || - ((partToEval.at(0) == '-' || partToEval.at(0) == '+') && - partToEval.size() > 1)) { - // Add the value to the RPN queue - rpnQueue.push_back( - Misc::precise_to_string(Misc::modifier(partToEval))); - // Identify the type as a value - qType.push_back('V'); - // If it is not a digit, check that it is not a parameter - } - else if ([&]() { - // Check if the parameter exists - if (params.count(ParameterName(partToEval, subc)) != 0) { - if (params.at(ParameterName(partToEval, subc)).get_value()) { - return true; + if (eBefore && digitAfter && digitBeforeE) { + // Find next operator since this operator is not an operator + opLoc = expToEval.find_first_of("/*-+(){}[]^", opLoc + 1); } - return false; - } - return false; - }()) { - // If the parameter exists then add to the queue - rpnQueue.push_back(Misc::precise_to_string( - params.at(ParameterName(partToEval, subc)).get_value().value())); - // Identify the type as a value - qType.push_back('V'); - // Else check that it is not a function name such as SIN, COS, TAN, etc. - } - else if (std::find( - funcs.begin(), funcs.end(), partToEval) != funcs.end()) { - // Add it to the operator stack if it is - opStack.push_back(partToEval); - // If not a function, check if it is not a defined constant - } - else if (Misc::string_constant(partToEval) != 0.0) { - // Add this defined constant to the RPN stack - rpnQueue.push_back( - Misc::precise_to_string(Misc::string_constant(partToEval))); - // Identify the type as a value - qType.push_back('V'); - // If not a constant, check if it is an operator in the operator list - } - else if (partToEval.find_first_of("/*-+^") != std::string::npos) { - // While the operator stack is not empty - while ((!opStack.empty()) && - (((precedence_lvl(opStack.back()) == 4) || - (precedence_lvl(opStack.back()) >= - precedence_lvl(partToEval))) && - (opStack.back().find_first_of("([{") == std::string::npos) && - (partToEval != "^"))) { - // Add the operator to the RPN stack - rpnQueue.push_back(opStack.back()); - // Identify the type as operator - qType.push_back('O'); - // Remove the operator from the operator stack - opStack.pop_back(); + } } - // Add the part to be evaluated to the operator stack - opStack.push_back(partToEval); - // Check parenthesis opening - } - else if (partToEval.find_first_of("([{") != std::string::npos) { - // Add the parenthesis opening to the operator stack - opStack.push_back(partToEval); - // Check parenthesis close - } - else if (partToEval.find_first_of(")]}") != std::string::npos) { - // While operator stack is not empty and the back is not a opening - while ((!opStack.empty()) && - (opStack.back().find_first_of("([{") == std::string::npos)) { - // Add the operator to the RPN stack - rpnQueue.push_back(opStack.back()); - // Identify it as an operator - qType.push_back('O'); - // Remove the operator from the operator stack - opStack.pop_back(); - } - // Id the stack is not empty and the back is a closing - if ((!opStack.empty()) && - (opStack.back().find_first_of("([{") != std::string::npos)) { - // Remove from the operator stack - opStack.pop_back(); - // If this point is reached we have mismatched parenthesis - } - else { - Errors::parsing_errors( - ParsingErrors::MISMATCHED_PARENTHESIS, expr); - } - // Function is invalid or a parameter is used which is unparsed - } - else { - if (!single) { - // Return NaN to indicate this ocurred - return std::numeric_limits::quiet_NaN(); - } - else { - Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, expr); - } - } - // Adjust the next part to be evaluated - if (opLoc == 0) { - // If the operator is at 0, substring the rest of the expression - expToEval = expToEval.substr(1); - // If operator is not found then the remaining expression is empty - } - else if (opLoc == -1) { - expToEval = ""; - // Else substring until the next operator location - } - else { - expToEval = expToEval.substr(opLoc); + } } + } + // If the operator is at the start of the string + if (opLoc == 0) { + // The part to evaluate is the the operator + partToEval = expToEval.substr(0, opLoc + 1); + // If the operator is further along + } else { + // The part to evaluate is from the start to the the operator + partToEval = expToEval.substr(0, opLoc); + } } - // If the remaining expresiotn is empty - if (expToEval.empty()) - // If the operator stack is not empty (it should be) - while (!opStack.empty()) { - // If the last operator is an opening parenthesis - if (opStack.back().find_first_of("([{") != std::string::npos) - // We have mismatched parenthesis, complain - Errors::parsing_errors(ParsingErrors::MISMATCHED_PARENTHESIS, expr); - else { - // Add the operator to the RPN stack - rpnQueue.push_back(opStack.back()); - // Identify it as an operator - qType.push_back('O'); - // Remove the operator from the operator stack - opStack.pop_back(); - } + // Handle a numerical value + if (isdigit(partToEval.at(0)) || + ((partToEval.at(0) == '-' || partToEval.at(0) == '+') && + partToEval.size() > 1)) { + // Add the value to the RPN queue + rpnQueue.push_back(Misc::precise_to_string(Misc::modifier(partToEval))); + // Identify the type as a value + qType.push_back('V'); + // If it is not a digit, check that it is not a parameter + } else if ([&]() { + // Check if the parameter exists + if (params.count(ParameterName(partToEval, subc)) != 0) { + if (params.at(ParameterName(partToEval, subc)).get_value()) { + return true; + } + return false; + } + return false; + }()) { + // If the parameter exists then add to the queue + rpnQueue.push_back(Misc::precise_to_string( + params.at(ParameterName(partToEval, subc)).get_value().value())); + // Identify the type as a value + qType.push_back('V'); + // Else check that it is not a function name such as SIN, COS, TAN, etc. + } else if (std::find(funcs.begin(), funcs.end(), partToEval) != + funcs.end()) { + // Add it to the operator stack if it is + opStack.push_back(partToEval); + // If not a function, check if it is not a defined constant + } else if (Misc::string_constant(partToEval) != 0.0) { + // Add this defined constant to the RPN stack + rpnQueue.push_back( + Misc::precise_to_string(Misc::string_constant(partToEval))); + // Identify the type as a value + qType.push_back('V'); + // If not a constant, check if it is an operator in the operator list + } else if (partToEval.find_first_of("/*-+^") != std::string::npos) { + // While the operator stack is not empty + while ( + (!opStack.empty()) && + (((precedence_lvl(opStack.back()) == 4) || + (precedence_lvl(opStack.back()) >= precedence_lvl(partToEval))) && + (opStack.back().find_first_of("([{") == std::string::npos) && + (partToEval != "^"))) { + // Add the operator to the RPN stack + rpnQueue.push_back(opStack.back()); + // Identify the type as operator + qType.push_back('O'); + // Remove the operator from the operator stack + opStack.pop_back(); + } + // Add the part to be evaluated to the operator stack + opStack.push_back(partToEval); + // Check parenthesis opening + } else if (partToEval.find_first_of("([{") != std::string::npos) { + // Add the parenthesis opening to the operator stack + opStack.push_back(partToEval); + // Check parenthesis close + } else if (partToEval.find_first_of(")]}") != std::string::npos) { + // While operator stack is not empty and the back is not a opening + while ((!opStack.empty()) && + (opStack.back().find_first_of("([{") == std::string::npos)) { + // Add the operator to the RPN stack + rpnQueue.push_back(opStack.back()); + // Identify it as an operator + qType.push_back('O'); + // Remove the operator from the operator stack + opStack.pop_back(); + } + // Id the stack is not empty and the back is a closing + if ((!opStack.empty()) && + (opStack.back().find_first_of("([{") != std::string::npos)) { + // Remove from the operator stack + opStack.pop_back(); + // If this point is reached we have mismatched parenthesis + } else { + Errors::parsing_errors(ParsingErrors::MISMATCHED_PARENTHESIS, expr); + } + // Function is invalid or a parameter is used which is unparsed + } else { + if (!single) { + // Return NaN to indicate this ocurred + return std::numeric_limits::quiet_NaN(); + } else { + Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, expr); + } + } + // Adjust the next part to be evaluated + if (opLoc == 0) { + // If the operator is at 0, substring the rest of the expression + expToEval = expToEval.substr(1); + // If operator is not found then the remaining expression is empty + } else if (opLoc == -1) { + expToEval = ""; + // Else substring until the next operator location + } else { + expToEval = expToEval.substr(opLoc); + } + } + // If the remaining expresiotn is empty + if (expToEval.empty()) + // If the operator stack is not empty (it should be) + while (!opStack.empty()) { + // If the last operator is an opening parenthesis + if (opStack.back().find_first_of("([{") != std::string::npos) + // We have mismatched parenthesis, complain + Errors::parsing_errors(ParsingErrors::MISMATCHED_PARENTHESIS, expr); + else { + // Add the operator to the RPN stack + rpnQueue.push_back(opStack.back()); + // Identify it as an operator + qType.push_back('O'); + // Remove the operator from the operator stack + opStack.pop_back(); + } + } + // Perform Reverse Polish Notation expansion on RPN stack + while (rpnQueue.size() > 1) { + // Clear the copies + rpnQueueCopy.clear(); + qTypeCopy.clear(); + // Loop the the queue type + for (int64_t i = 0; i < qType.size(); ++i) { + // If the queue type is value + if (qType[i] == 'V') { + // Add the value to the copy of the RPN + rpnQueueCopy.push_back(rpnQueue[i]); + // Add the type to the copy of the qType + qTypeCopy.push_back('V'); + // If the type is operator + } else if (qType[i] == 'O') { + // If the operator is the first item in the queue + if (i == 0) { + // We have an invalid queue type. Should always be VVO or VO + Errors::parsing_errors(ParsingErrors::INVALID_RPN, expr); + // If we are less than 2 deep in the stack + } else if (i < 2) { + // Remove the previous value from the copy + rpnQueueCopy.pop_back(); + // Process the operator on the value and add to the copy + rpnQueueCopy.push_back(Misc::precise_to_string(parse_operator( + rpnQueue[i], 0, Misc::modifier(rpnQueue[i - 1]), popCount))); + // Now proceed as normal with RPN expansion + } else { + // Evaluate the operator on the two values + result = parse_operator(rpnQueue[i], Misc::modifier(rpnQueue[i - 2]), + Misc::modifier(rpnQueue[i - 1]), popCount); + // Remove the two values from the copy + for (int64_t k = 0; k < popCount; ++k) { + rpnQueueCopy.pop_back(); + } + // If we removed two + if (popCount == 2) { + // Remove the type from the copy of type stack + qTypeCopy.pop_back(); + } + // Add the result value to the RPN queue + rpnQueueCopy.push_back(Misc::precise_to_string(result)); } - // Perform Reverse Polish Notation expansion on RPN stack - while (rpnQueue.size() > 1) { - // Clear the copies - rpnQueueCopy.clear(); - qTypeCopy.clear(); - // Loop the the queue type - for (int64_t i = 0; i < qType.size(); ++i) { - // If the queue type is value - if (qType[i] == 'V') { - // Add the value to the copy of the RPN - rpnQueueCopy.push_back(rpnQueue[i]); - // Add the type to the copy of the qType - qTypeCopy.push_back('V'); - // If the type is operator - } - else if (qType[i] == 'O') { - // If the operator is the first item in the queue - if (i == 0) { - // We have an invalid queue type. Should always be VVO or VO - Errors::parsing_errors(ParsingErrors::INVALID_RPN, expr); - // If we are less than 2 deep in the stack - } - else if (i < 2) { - // Remove the previous value from the copy - rpnQueueCopy.pop_back(); - // Process the operator on the value and add to the copy - rpnQueueCopy.push_back(Misc::precise_to_string(parse_operator( - rpnQueue[i], 0, Misc::modifier(rpnQueue[i - 1]), popCount))); - // Now proceed as normal with RPN expansion - } - else { - // Evaluate the operator on the two values - result = parse_operator(rpnQueue[i], Misc::modifier(rpnQueue[i - 2]), - Misc::modifier(rpnQueue[i - 1]), popCount); - // Remove the two values from the copy - for (int64_t k = 0; k < popCount; ++k) { - rpnQueueCopy.pop_back(); - } - // If we removed two - if (popCount == 2) { - // Remove the type from the copy of type stack - qTypeCopy.pop_back(); - } - // Add the result value to the RPN queue - rpnQueueCopy.push_back(Misc::precise_to_string(result)); - } - // If the RPN queue is greater or equal to i - if (rpnQueue.size() >= i) { - // Insert the rest of the stacks to the copies - rpnQueueCopy.insert(rpnQueueCopy.end(), rpnQueue.begin() + i + 1, - rpnQueue.end()); - qTypeCopy.insert( - qTypeCopy.end(), qType.begin() + i + 1, qType.end()); - } - break; - } + // If the RPN queue is greater or equal to i + if (rpnQueue.size() >= i) { + // Insert the rest of the stacks to the copies + rpnQueueCopy.insert(rpnQueueCopy.end(), rpnQueue.begin() + i + 1, + rpnQueue.end()); + qTypeCopy.insert(qTypeCopy.end(), qType.begin() + i + 1, qType.end()); } - rpnQueue = rpnQueueCopy; - qType = qTypeCopy; + break; + } } - // The final value should be the one we want, return this - return Misc::modifier(rpnQueue.back()); + rpnQueue = rpnQueueCopy; + qType = qTypeCopy; + } + // The final value should be the one we want, return this + return Misc::modifier(rpnQueue.back()); } - -double JoSIM::parse_operator( - const std::string& op, double val1, double val2, int64_t& popCount) { - if (std::find(funcs.begin(), funcs.end(), op) != funcs.end()) { - popCount = 1; - if (op == "SIN") - return sin(val2); - else if (op == "COS") - return cos(val2); - else if (op == "TAN") - return tan(val2); - else if (op == "ASIN") - return asin(val2); - else if (op == "ACOS") - return acos(val2); - else if (op == "ATAN") - return atan(val2); - else if (op == "SINH") - return sinh(val2); - else if (op == "COSH") - return cosh(val2); - else if (op == "TANH") - return tanh(val2); - else if (op == "ASINH") - return asinh(val2); - else if (op == "ACOSH") - return acosh(val2); - else if (op == "ATANH") - return atanh(val2); - else if (op == "EXP") - return exp(val2); - else if (op == "LOG") - return log(val2); - else if (op == "SQRT") - return sqrt(val2); - else if (op == "CBRT") - return cbrt(val2); - } - else { - popCount = 2; - switch (op.at(0)) { - case '+': - return val1 + val2; - case '-': - return val1 - val2; - case '*': - return val1 * val2; - case '/': - return val1 / val2; - case '^': - return pow(val1, val2); - } +double JoSIM::parse_operator(const std::string& op, double val1, double val2, + int64_t& popCount) { + if (std::find(funcs.begin(), funcs.end(), op) != funcs.end()) { + popCount = 1; + if (op == "SIN") + return sin(val2); + else if (op == "COS") + return cos(val2); + else if (op == "TAN") + return tan(val2); + else if (op == "ASIN") + return asin(val2); + else if (op == "ACOS") + return acos(val2); + else if (op == "ATAN") + return atan(val2); + else if (op == "SINH") + return sinh(val2); + else if (op == "COSH") + return cosh(val2); + else if (op == "TANH") + return tanh(val2); + else if (op == "ASINH") + return asinh(val2); + else if (op == "ACOSH") + return acosh(val2); + else if (op == "ATANH") + return atanh(val2); + else if (op == "EXP") + return exp(val2); + else if (op == "LOG") + return log(val2); + else if (op == "SQRT") + return sqrt(val2); + else if (op == "CBRT") + return cbrt(val2); + } else { + popCount = 2; + switch (op.at(0)) { + case '+': + return val1 + val2; + case '-': + return val1 - val2; + case '*': + return val1 * val2; + case '/': + return val1 / val2; + case '^': + return pow(val1, val2); } - return 0.0; + } + return 0.0; } void JoSIM::parse_parameters(param_map& parameters) { - // Double parsed value that will be stored for each parameter - double value; - // Counter to ensure that we do not get stuck in a loop - int64_t parsedCounter = 0; - // Parse parameters while counter is less than total parameter count - while (parsedCounter < parameters.size()) { - // Set previous counter to counter to do sanity check - int64_t previous_counter = parsedCounter; - // Loop through the parameters parsing them if possible - for (auto& i : parameters) { - // If the parameter does not yet have a value (double) - if (!i.second.get_value()) { - // Parse this parameter if expression if possible - value = parse_param( - i.second.get_expression(), parameters, i.first.subcircuit(), false); - // If the returned value is not NaN - if (!std::isnan(value)) { - // Set the parameter value (double) to the parsed value (double) - i.second.set_value(value); - // Increase the counter - parsedCounter++; - } - } + // Double parsed value that will be stored for each parameter + double value; + // Counter to ensure that we do not get stuck in a loop + int64_t parsedCounter = 0; + // Parse parameters while counter is less than total parameter count + while (parsedCounter < parameters.size()) { + // Set previous counter to counter to do sanity check + int64_t previous_counter = parsedCounter; + // Loop through the parameters parsing them if possible + for (auto& i : parameters) { + // If the parameter does not yet have a value (double) + if (!i.second.get_value()) { + // Parse this parameter if expression if possible + value = parse_param(i.second.get_expression(), parameters, + i.first.subcircuit(), false); + // If the returned value is not NaN + if (!std::isnan(value)) { + // Set the parameter value (double) to the parsed value (double) + i.second.set_value(value); + // Increase the counter + parsedCounter++; } - // If we reach this then there are parameters that could not be parsed - if (previous_counter == parsedCounter) { - // Temporary string that will contain the parameter to complain about - std::string unknownParams; - // Loop through the parameters - for (auto& i : parameters) { - // If there are parameters with no value (double) - if (!i.second.get_value()) { - // Create a string with the name and subcircuit - unknownParams += - i.first.name() + " " + i.first.subcircuit().value_or("") + "\n"; - } - } - // Complain about all the unknown parameters only once - Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, unknownParams); + } + } + // If we reach this then there are parameters that could not be parsed + if (previous_counter == parsedCounter) { + // Temporary string that will contain the parameter to complain about + std::string unknownParams; + // Loop through the parameters + for (auto& i : parameters) { + // If there are parameters with no value (double) + if (!i.second.get_value()) { + // Create a string with the name and subcircuit + unknownParams += + i.first.name() + " " + i.first.subcircuit().value_or("") + "\n"; } + } + // Complain about all the unknown parameters only once + Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, unknownParams); } - + } } void JoSIM::update_parameters(param_map& parameters) { - // Reset all the paraemeter values (doubles) - for (auto i : parameters) { - i.second.set_value(std::nan("")); - } - // Parse all the parameters again - parse_parameters(parameters); + // Reset all the paraemeter values (doubles) + for (auto i : parameters) { + i.second.set_value(std::nan("")); + } + // Parse all the parameters again + parse_parameters(parameters); } -void JoSIM::expand_inline_parameters( - std::pair& s, param_map& parameters) { - int_o oPos, cPos; - // Loop through all the provided tokens, expanding any parameters - for (int64_t i = 0; i < s.first.size(); ++i) { - // If there exists a opening curly parenthesis, an expression exists - if (s.first.at(i).find("{") != std::string::npos) { - oPos = i; - } - // If there exists a closing curly parenthesis, an expression exists - if (s.first.at(i).find("}") != std::string::npos) { - cPos = i; - } +void JoSIM::expand_inline_parameters(std::pair& s, + param_map& parameters) { + int_o oPos, cPos; + // Loop through all the provided tokens, expanding any parameters + for (int64_t i = 0; i < s.first.size(); ++i) { + // If there exists a opening curly parenthesis, an expression exists + if (s.first.at(i).find("{") != std::string::npos) { + oPos = i; } - // If an expression opening was found - if (oPos) { - // Then a closing brace must exist - if (!cPos) { - // Complain if it doesn't - Errors::parsing_errors( - ParsingErrors::INVALID_DECLARATION, Misc::vector_to_string(s.first)); - } - if (cPos.value() != oPos.value()) { - s.first.at(oPos.value()) = Misc::vector_to_string( - tokens_t{ s.first.begin() + oPos.value(), - s.first.begin() + cPos.value() + 1 }, ""); - s.first.erase(s.first.begin() + oPos.value() + 1, - s.first.begin() + cPos.value() + 1); - } - tokens_t temp = Misc::tokenize(s.first.at(oPos.value()), "{}", true, true, 2); - double value = parse_param(temp.back(), parameters, s.second, false); - // If the returned value is not NaN - if (std::isnan(value)) { - // Complain of invalid parameter expression - Errors::parsing_errors( - ParsingErrors::UNIDENTIFIED_PART, Misc::vector_to_string(s.first)); - } - // Erase the expression part of the tokens - s.first.erase( - s.first.begin() + oPos.value(), s.first.begin() + oPos.value() + 1); - if (temp.size() > 1) { - // Insert the double value in the place of the expression - s.first.insert(s.first.begin() + oPos.value(), - Misc::vector_to_string( - tokens_t{ temp.front(), Misc::precise_to_string(value) }, "")); - } - else { - s.first.insert(s.first.begin() + oPos.value(), - Misc::precise_to_string(value)); - } + // If there exists a closing curly parenthesis, an expression exists + if (s.first.at(i).find("}") != std::string::npos) { + cPos = i; } - // If an expression closing was found - if (cPos) { - // Then a opening brace must exist - if (!oPos) { - // Complain if it doesn't - Errors::parsing_errors( - ParsingErrors::INVALID_DECLARATION, Misc::vector_to_string(s.first)); - } + } + // If an expression opening was found + if (oPos) { + // Then a closing brace must exist + if (!cPos) { + // Complain if it doesn't + Errors::parsing_errors(ParsingErrors::INVALID_DECLARATION, + Misc::vector_to_string(s.first)); + } + if (cPos.value() != oPos.value()) { + s.first.at(oPos.value()) = + Misc::vector_to_string(tokens_t{s.first.begin() + oPos.value(), + s.first.begin() + cPos.value() + 1}, + ""); + s.first.erase(s.first.begin() + oPos.value() + 1, + s.first.begin() + cPos.value() + 1); + } + tokens_t temp = + Misc::tokenize(s.first.at(oPos.value()), "{}", true, true, 2); + double value = parse_param(temp.back(), parameters, s.second, false); + // If the returned value is not NaN + if (std::isnan(value)) { + // Complain of invalid parameter expression + Errors::parsing_errors(ParsingErrors::UNIDENTIFIED_PART, + Misc::vector_to_string(s.first)); + } + // Erase the expression part of the tokens + s.first.erase(s.first.begin() + oPos.value(), + s.first.begin() + oPos.value() + 1); + if (temp.size() > 1) { + // Insert the double value in the place of the expression + s.first.insert( + s.first.begin() + oPos.value(), + Misc::vector_to_string( + tokens_t{temp.front(), Misc::precise_to_string(value)}, "")); + } else { + s.first.insert(s.first.begin() + oPos.value(), + Misc::precise_to_string(value)); + } + } + // If an expression closing was found + if (cPos) { + // Then a opening brace must exist + if (!oPos) { + // Complain if it doesn't + Errors::parsing_errors(ParsingErrors::INVALID_DECLARATION, + Misc::vector_to_string(s.first)); } + } } \ No newline at end of file diff --git a/src/PhaseSource.cpp b/src/PhaseSource.cpp index 8a895e85..1f531c3a 100644 --- a/src/PhaseSource.cpp +++ b/src/PhaseSource.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/PhaseSource.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -18,14 +19,14 @@ using namespace JoSIM; ⎣ 1 -1 0⎦ ⎣Io⎦ ⎣ 0⎦ */ -PhaseSource::PhaseSource( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, int64_t& bi, const int64_t& si) { +PhaseSource::PhaseSource(const std::pair& s, + const NodeConfig& ncon, const nodemap& nm, + std::unordered_set& lm, + nodeconnections& nc, int64_t& bi, const int64_t& si) { // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); diff --git a/src/RelevantTrace.cpp b/src/RelevantTrace.cpp index 49a75c5a..0f2273e6 100644 --- a/src/RelevantTrace.cpp +++ b/src/RelevantTrace.cpp @@ -2,11 +2,12 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/RelevantTrace.hpp" -#include "JoSIM/Matrix.hpp" -#include "JoSIM/Input.hpp" #include +#include "JoSIM/Input.hpp" +#include "JoSIM/Matrix.hpp" + using namespace JoSIM; void JoSIM::find_relevant_traces(Input& iObj, Matrix& mObj) { @@ -16,15 +17,14 @@ void JoSIM::find_relevant_traces(Input& iObj, Matrix& mObj) { std::vector& c = iObj.controls; // Loop through and handle plot, print and save commands for (int64_t i = 0; i < c.size(); ++i) { - if ((c.at(i).front() == "PRINT") || - (c.at(i).front() == "PLOT") || - (c.at(i).front() == "SAVE")) { + if ((c.at(i).front() == "PRINT") || (c.at(i).front() == "PLOT") || + (c.at(i).front() == "SAVE")) { // Mutable version of the control line tokens tokens_t t = c.at(i); // Ensure that the store command conforms to syntax if (t.size() < 2 && t.at(0) != "SAVE") { - Errors::control_errors( - ControlErrors::INVALID_OUTPUT_COMMAND, Misc::vector_to_string(t)); + Errors::control_errors(ControlErrors::INVALID_OUTPUT_COMMAND, + Misc::vector_to_string(t)); } // Fix any naming issues, '.' should be '|' for (auto& l : t) { @@ -32,107 +32,107 @@ void JoSIM::find_relevant_traces(Input& iObj, Matrix& mObj) { std::replace(l.begin(), l.end(), '.', '|'); } } - // Remove any "TRAN" tokens. We don't do that here. + // Remove any "TRAN" tokens. We don't do that here. for (int64_t j = 0; j < t.size(); ++j) { if (t.at(j) == "TRAN") t.erase(t.begin() + j); } // Determine the type of plot for (int64_t j = 1; j < t.size(); ++j) { switch (t.at(j).back()) { - case ')': - switch (t.at(j).at(0)) { - case 'I': - t.at(j).erase(0, 2); - t.at(j).erase(t.at(j).size() - 1, t.at(j).size()); - handle_current(t.at(j), mObj, fIndex); + case ')': + switch (t.at(j).at(0)) { + case 'I': + t.at(j).erase(0, 2); + t.at(j).erase(t.at(j).size() - 1, t.at(j).size()); + handle_current(t.at(j), mObj, fIndex); + break; + case 'V': + t.at(j).erase(0, 2); + t.at(j).erase(t.at(j).size() - 1, t.at(j).size()); + handle_voltage_or_phase(t.at(j), true, mObj, fIndex); + break; + case 'P': + t.at(j).erase(0, 2); + t.at(j).erase(t.at(j).size() - 1, t.at(j).size()); + handle_voltage_or_phase(t.at(j), false, mObj, fIndex); + break; + } break; case 'V': - t.at(j).erase(0, 2); - t.at(j).erase(t.at(j).size() - 1, t.at(j).size()); - handle_voltage_or_phase(t.at(j), true, mObj, fIndex); - break; - case 'P': - t.at(j).erase(0, 2); - t.at(j).erase(t.at(j).size() - 1, t.at(j).size()); - handle_voltage_or_phase(t.at(j), false, mObj, fIndex); + if (t.size() < 4) { + handle_voltage_or_phase(t.at(j + 1), true, mObj, fIndex); + } else { + handle_voltage_or_phase(t.at(j + 1) + " " + t.at(j + 2), true, + mObj, fIndex); + } + j = t.size(); break; - } - break; - case 'V': - if (t.size() < 4) { - handle_voltage_or_phase(t.at(j + 1), true, mObj, fIndex); - } else { - handle_voltage_or_phase( - t.at(j + 1) + " " + t.at(j + 2), true, mObj, fIndex); - } - j = t.size(); - break; - case 'E': - handle_voltage_or_phase(t.at(j + 1), false, mObj, fIndex); - j = t.size(); - break; - case 'P': - if (t.size() < 4) { + case 'E': handle_voltage_or_phase(t.at(j + 1), false, mObj, fIndex); - } else { - handle_voltage_or_phase( - t.at(j + 1) + " " + t.at(j + 2), false, mObj, fIndex); - } - j = t.size(); - break; - case 'I': - handle_current(t.at(j + 1), mObj, fIndex); - j = t.size(); - break; - case 'H': - if (t.at(j).find("#BRANCH") != std::string::npos) { - t.at(j) = t.at(j).substr(0, t.at(j).find("#BRANCH")); - handle_current(t.at(j), mObj, fIndex); + j = t.size(); break; - } else { - Errors::control_errors( - ControlErrors::INVALID_OUTPUT_COMMAND, - t.at(j) + " in line:\n" + Misc::vector_to_string(c.at(i))); + case 'P': + if (t.size() < 4) { + handle_voltage_or_phase(t.at(j + 1), false, mObj, fIndex); + } else { + handle_voltage_or_phase(t.at(j + 1) + " " + t.at(j + 2), false, + mObj, fIndex); + } + j = t.size(); break; - } - case ']': - if (t.at(j).at(0) == '@') { - switch (t.at(j).at(t.at(j).size() - 2)) { - case 'C': - t.at(j).erase(0, 1); - t.at(j).erase(t.at(j).size() - 3, t.at(j).size()); + case 'I': + handle_current(t.at(j + 1), mObj, fIndex); + j = t.size(); + break; + case 'H': + if (t.at(j).find("#BRANCH") != std::string::npos) { + t.at(j) = t.at(j).substr(0, t.at(j).find("#BRANCH")); handle_current(t.at(j), mObj, fIndex); break; - case 'V': - t.at(j).erase(0, 1); - t.at(j).erase(t.at(j).size() - 3, t.at(j).size()); - handle_voltage_or_phase(t.at(j), true, mObj, fIndex); + } else { + Errors::control_errors( + ControlErrors::INVALID_OUTPUT_COMMAND, + t.at(j) + " in line:\n" + Misc::vector_to_string(c.at(i))); + break; + } + case ']': + if (t.at(j).at(0) == '@') { + switch (t.at(j).at(t.at(j).size() - 2)) { + case 'C': + t.at(j).erase(0, 1); + t.at(j).erase(t.at(j).size() - 3, t.at(j).size()); + handle_current(t.at(j), mObj, fIndex); + break; + case 'V': + t.at(j).erase(0, 1); + t.at(j).erase(t.at(j).size() - 3, t.at(j).size()); + handle_voltage_or_phase(t.at(j), true, mObj, fIndex); + break; + case 'P': + t.at(j).erase(0, 1); + t.at(j).erase(t.at(j).size() - 3, t.at(j).size()); + handle_voltage_or_phase(t.at(j), false, mObj, fIndex); + break; + } break; - case 'P': - t.at(j).erase(0, 1); - t.at(j).erase(t.at(j).size() - 3, t.at(j).size()); - handle_voltage_or_phase(t.at(j), false, mObj, fIndex); + } else { + Errors::control_errors( + ControlErrors::INVALID_OUTPUT_COMMAND, + t.at(j) + " in line:\n" + Misc::vector_to_string(c.at(i))); break; } - break; - } else { + default: Errors::control_errors( - ControlErrors::INVALID_OUTPUT_COMMAND, - t.at(j) + " in line:\n" + Misc::vector_to_string(c.at(i))); + ControlErrors::INVALID_OUTPUT_COMMAND, + t.at(j) + " in line:\n" + Misc::vector_to_string(c.at(i))); break; - } - default: - Errors::control_errors( - ControlErrors::INVALID_OUTPUT_COMMAND, - t.at(j) + " in line:\n" + Misc::vector_to_string(c.at(i))); - break; } if (t.at(1) == "NODE") { break; } } } else if (c.at(i).front() == "FILE") { - fIndex++; + fIndex++; } } // Store the indices of the identified traces @@ -150,7 +150,7 @@ void JoSIM::find_relevant_traces(Input& iObj, Matrix& mObj) { // Store the indices of all the transmission lines for (const auto& i : mObj.components.txIndices) { const auto& tempLocal = - std::get(mObj.components.devices.at(i)); + std::get(mObj.components.devices.at(i)); if (tempLocal.indexInfo.posIndex_) { mObj.relevantIndices.emplace_back(tempLocal.indexInfo.posIndex_.value()); } @@ -164,13 +164,13 @@ void JoSIM::find_relevant_traces(Input& iObj, Matrix& mObj) { mObj.relevantIndices.emplace_back(tempLocal.negIndex2_.value()); } mObj.relevantIndices.emplace_back( - tempLocal.indexInfo.currentIndex_.value()); + tempLocal.indexInfo.currentIndex_.value()); mObj.relevantIndices.emplace_back(tempLocal.currentIndex2_); } // Remove any dupicate indices used for storing mObj.relevantIndices.erase( - uniquify(mObj.relevantIndices.begin(), mObj.relevantIndices.end()), - mObj.relevantIndices.end()); + uniquify(mObj.relevantIndices.begin(), mObj.relevantIndices.end()), + mObj.relevantIndices.end()); } void JoSIM::handle_current(const std::string& s, Matrix& mObj, int64_t fIndex) { @@ -179,18 +179,20 @@ void JoSIM::handle_current(const std::string& s, Matrix& mObj, int64_t fIndex) { temp.storageType = StorageType::Current; if (s.at(0) != 'I') { for (int64_t j = 0; j < mObj.components.devices.size(); ++j) { - const auto& l = - std::visit([](const auto& device) noexcept -> const std::string& { - return device.netlistInfo.label_; - }, mObj.components.devices.at(j)); + const auto& l = std::visit( + [](const auto& device) noexcept -> const std::string& { + return device.netlistInfo.label_; + }, + mObj.components.devices.at(j)); if (l == s) { temp.deviceLabel = "\"I(" + s + ")\""; temp.device = true; temp.index1 = std::visit( - [](const auto& device) noexcept -> const int64_t& { - return device.indexInfo.currentIndex_.value(); - }, mObj.components.devices.at(j)); + [](const auto& device) noexcept -> const int64_t& { + return device.indexInfo.currentIndex_.value(); + }, + mObj.components.devices.at(j)); mObj.relevantTraces.emplace_back(temp); break; } @@ -211,8 +213,8 @@ void JoSIM::handle_current(const std::string& s, Matrix& mObj, int64_t fIndex) { } } -void JoSIM::handle_voltage_or_phase( - const std::string& s, bool voltage, Matrix& mObj, int64_t fIndex) { +void JoSIM::handle_voltage_or_phase(const std::string& s, bool voltage, + Matrix& mObj, int64_t fIndex) { std::vector tokens = Misc::tokenize(s, " ,"); RelevantTrace temp; temp.fIndex = fIndex; @@ -223,9 +225,10 @@ void JoSIM::handle_voltage_or_phase( } for (int64_t j = 0; j < mObj.components.devices.size(); ++j) { const auto& l = std::visit( - [](const auto& device) noexcept -> const std::string& { - return device.netlistInfo.label_; - }, mObj.components.devices.at(j)); + [](const auto& device) noexcept -> const std::string& { + return device.netlistInfo.label_; + }, + mObj.components.devices.at(j)); if (l == tokens.at(0)) { if (tokens.size() < 1) { @@ -238,14 +241,16 @@ void JoSIM::handle_voltage_or_phase( temp.deviceLabel = "\"P(" + s + ")\""; } temp.device = true; - temp.index1 = - std::visit([](const auto& device) noexcept -> const int_o& { - return device.indexInfo.posIndex_; - }, mObj.components.devices.at(j)); - temp.index2 = - std::visit([](const auto& device) noexcept -> const int_o& { - return device.indexInfo.negIndex_; - }, mObj.components.devices.at(j)); + temp.index1 = std::visit( + [](const auto& device) noexcept -> const int_o& { + return device.indexInfo.posIndex_; + }, + mObj.components.devices.at(j)); + temp.index2 = std::visit( + [](const auto& device) noexcept -> const int_o& { + return device.indexInfo.negIndex_; + }, + mObj.components.devices.at(j)); mObj.relevantTraces.emplace_back(temp); break; } else { @@ -255,17 +260,19 @@ void JoSIM::handle_voltage_or_phase( temp.deviceLabel = "\"P(" + s + ")\""; } temp.device = true; - temp.index1 = - std::visit([](const auto& device) noexcept -> const int_o& { - return device.indexInfo.posIndex_; - }, mObj.components.devices.at(j)); - temp.index2 = - std::visit([](const auto& device) noexcept -> const int_o& { - return device.indexInfo.negIndex_; - }, mObj.components.devices.at(j)); + temp.index1 = std::visit( + [](const auto& device) noexcept -> const int_o& { + return device.indexInfo.posIndex_; + }, + mObj.components.devices.at(j)); + temp.index2 = std::visit( + [](const auto& device) noexcept -> const int_o& { + return device.indexInfo.negIndex_; + }, + mObj.components.devices.at(j)); try { temp.variableIndex = - std::get(mObj.components.devices.at(j)).variableIndex_; + std::get(mObj.components.devices.at(j)).variableIndex_; mObj.relevantTraces.emplace_back(temp); break; } catch (const std::bad_variant_access&) { @@ -282,22 +289,19 @@ void JoSIM::handle_voltage_or_phase( temp.index2 = mObj.nm.at(tokens.at(1)); } else { if (tokens.at(1) != "0" && - tokens.at(1).find("GND") == std::string::npos) { - Errors::control_errors( - ControlErrors::UNKNOWN_DEVICE, tokens.at(1)); + tokens.at(1).find("GND") == std::string::npos) { + Errors::control_errors(ControlErrors::UNKNOWN_DEVICE, tokens.at(1)); } } if (voltage) { - temp.deviceLabel = - "\"V(" + tokens.at(0) + "," + tokens.at(1) + ")\""; + temp.deviceLabel = "\"V(" + tokens.at(0) + "," + tokens.at(1) + ")\""; } else { - temp.deviceLabel = - "\"P(" + tokens.at(0) + "," + tokens.at(1) + ")\""; + temp.deviceLabel = "\"P(" + tokens.at(0) + "," + tokens.at(1) + ")\""; } mObj.relevantTraces.emplace_back(temp); } else { if (tokens.at(0) != "0" && - tokens.at(0).find("GND") == std::string::npos) { + tokens.at(0).find("GND") == std::string::npos) { Errors::control_errors(ControlErrors::UNKNOWN_DEVICE, tokens.at(0)); } } diff --git a/src/Resistor.cpp b/src/Resistor.cpp index 5ac63056..745d1940 100644 --- a/src/Resistor.cpp +++ b/src/Resistor.cpp @@ -2,13 +2,14 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Resistor.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" -#include "JoSIM/Noise.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/Noise.hpp" + using namespace JoSIM; /* @@ -27,10 +28,10 @@ using namespace JoSIM; ⎣ 1 -1 -R(2e/hbar)(2h/3)⎦ ⎣Io⎦ ⎣ (4/3)φn-1 - (1/3)φn-2⎦ */ -Resistor::Resistor( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, nodeconnections& nc, - Input& iObj, Spread& spread, int64_t& bi) { +Resistor::Resistor(const std::pair& s, + const NodeConfig& ncon, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + Input& iObj, Spread& spread, int64_t& bi) { double spr = 1.0; for (int64_t i = 4; i < s.first.size(); ++i) { auto& t = s.first.at(i); @@ -51,8 +52,8 @@ Resistor::Resistor( at_ = iObj.argAnal; // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -60,7 +61,7 @@ Resistor::Resistor( lm.emplace(s.first.at(0)); // Set the value (Resistance), this should be the 4th token netlistInfo.value_ = spread.spread_value( - parse_param(s.first.at(3), iObj.parameters, s.second), Spread::RES, spr); + parse_param(s.first.at(3), iObj.parameters, s.second), Spread::RES, spr); // Set the node configuration type indexInfo.nodeConfig_ = ncon; // Set current index and increment it @@ -77,17 +78,17 @@ Resistor::Resistor( // Set the value of node n-2 to 0 pn2_ = 0; // If phase mdoe analysis then append -((2*h)/3) * (R/σ) - matrixInfo.nonZeros_.emplace_back( - -((2.0 * iObj.transSim.tstep()) / 3.0) * - (netlistInfo.value_ / Constants::SIGMA)); + matrixInfo.nonZeros_.emplace_back(-((2.0 * iObj.transSim.tstep()) / 3.0) * + (netlistInfo.value_ / Constants::SIGMA)); } if (temp_) { - spAmp_ = Noise::determine_spectral_amplitude( - netlistInfo.value_, temp_.value()); + spAmp_ = + Noise::determine_spectral_amplitude(netlistInfo.value_, temp_.value()); Function tnoise; - tnoise.parse_function("NOISE(" + - Misc::precise_to_string(spAmp_.value()) + ", 0.0, " + - Misc::precise_to_string(1.0 / neb_.value()) + ")", iObj, s.second); + tnoise.parse_function("NOISE(" + Misc::precise_to_string(spAmp_.value()) + + ", 0.0, " + + Misc::precise_to_string(1.0 / neb_.value()) + ")", + iObj, s.second); thermalNoise = tnoise; } } @@ -95,7 +96,6 @@ Resistor::Resistor( // Update timestep based on a scalar factor i.e 0.5 for half the timestep void Resistor::update_timestep(const double& factor) { if (at_ == AnalysisType::Phase) { - matrixInfo.nonZeros_.back() = - factor * factor * matrixInfo.nonZeros_.back(); + matrixInfo.nonZeros_.back() = factor * factor * matrixInfo.nonZeros_.back(); } } \ No newline at end of file diff --git a/src/Simulation.cpp b/src/Simulation.cpp index a43f3492..a0097517 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -2,16 +2,17 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Simulation.hpp" + +#include +#include + #include "JoSIM/AnalysisType.hpp" #include "JoSIM/Components.hpp" -#include "JoSIM/Matrix.hpp" #include "JoSIM/Constants.hpp" +#include "JoSIM/Matrix.hpp" #include "JoSIM/Model.hpp" #include "JoSIM/ProgressBar.hpp" -#include -#include - using namespace JoSIM; Simulation::Simulation(Input &iObj, Matrix &mObj) { @@ -27,11 +28,10 @@ Simulation::Simulation(Input &iObj, Matrix &mObj) { // KLU setup simOK_ = klu_l_defaults(&Common_); assert(simOK_); - Symbolic_ = klu_l_analyze( - mObj.rp.size() - 1, &mObj.rp.front(), &mObj.ci.front(), &Common_); - Numeric_ = klu_l_factor( - &mObj.rp.front(), &mObj.ci.front(), &mObj.nz.front(), - Symbolic_, &Common_); + Symbolic_ = klu_l_analyze(mObj.rp.size() - 1, &mObj.rp.front(), + &mObj.ci.front(), &Common_); + Numeric_ = klu_l_factor(&mObj.rp.front(), &mObj.ci.front(), + &mObj.nz.front(), Symbolic_, &Common_); } // Run transient simulation @@ -53,7 +53,7 @@ Simulation::Simulation(Input &iObj, Matrix &mObj) { } } -void Simulation::setup(Input& iObj, Matrix& mObj) { +void Simulation::setup(Input &iObj, Matrix &mObj) { // Simulation setup SLU = iObj.SLU; simSize_ = iObj.transSim.simsize(); @@ -69,7 +69,7 @@ void Simulation::setup(Input& iObj, Matrix& mObj) { x_.resize(mObj.branchIndex, 0.0); if (!mObj.relevantTraces.empty()) { results.xVector.resize(mObj.branchIndex); - for (const auto& i : mObj.relevantIndices) { + for (const auto &i : mObj.relevantIndices) { results.xVector.at(i).emplace(); } } else { @@ -81,7 +81,7 @@ void Simulation::trans_sim(Matrix &mObj) { // Ensure time axis is cleared results.timeAxis.clear(); ProgressBar bar; - if(!minOut_) { + if (!minOut_) { bar.create_thread(); bar.set_bar_width(30); bar.fill_bar_progress_with("O"); @@ -106,19 +106,19 @@ void Simulation::trans_sim(Matrix &mObj) { if (SLU) { lu.solve(x_); } else { - simOK_ = klu_l_tsolve( - Symbolic_, Numeric_, mObj.rp.size() - 1, 1, &x_.front(), &Common_); + simOK_ = klu_l_tsolve(Symbolic_, Numeric_, mObj.rp.size() - 1, 1, + &x_.front(), &Common_); // If anything is a amiss, complain about it - if (!simOK_) Errors::simulation_errors( - SimulationErrors::MATRIX_SINGULAR); + if (!simOK_) + Errors::simulation_errors(SimulationErrors::MATRIX_SINGULAR); } } } // Start the simulation loop - for(int64_t i = 0; i < simSize_; ++i) { + for (int64_t i = 0; i < simSize_; ++i) { double step = i * stepSize_; // If not minimal printing report progress - if(!minOut_) { + if (!minOut_) { bar.update(static_cast(i)); } // Setup the b matrix @@ -130,55 +130,53 @@ void Simulation::trans_sim(Matrix &mObj) { if (SLU) { lu.solve(x_); } else { - simOK_ = klu_l_tsolve( - Symbolic_, Numeric_, mObj.rp.size() - 1, 1, &x_.front(), &Common_); + simOK_ = klu_l_tsolve(Symbolic_, Numeric_, mObj.rp.size() - 1, 1, + &x_.front(), &Common_); // If anything is a amiss, complain about it - if (!simOK_) Errors::simulation_errors( - SimulationErrors::MATRIX_SINGULAR); + if (!simOK_) Errors::simulation_errors(SimulationErrors::MATRIX_SINGULAR); } // Store results (only requested, to prevent massive memory usage) - for(int64_t j = 0; j < results.xVector.size(); ++j) { - if(results.xVector.at(j)) { + for (int64_t j = 0; j < results.xVector.size(); ++j) { + if (results.xVector.at(j)) { results.xVector.at(j).value().emplace_back(x_.at(j)); } } // Store the time step results.timeAxis.emplace_back(step); } - if(!minOut_) { + if (!minOut_) { bar.complete(); std::cout << "\n"; } } -void Simulation::reduce_step(Input& iObj, Matrix& mObj) { +void Simulation::reduce_step(Input &iObj, Matrix &mObj) { iObj.transSim.tstep(iObj.transSim.tstep() / 2); bool tempMinOut = iObj.argMin; if (!iObj.argMin) iObj.argMin = true; Matrix newmObj; mObj = newmObj; // Create the matrix in csr format - for (auto& i : mObj.sourcegen) { + for (auto &i : mObj.sourcegen) { i.clearMisc(); } mObj.create_matrix(iObj); find_relevant_traces(iObj, mObj); //// Dump expanded Netlist since it is no longer needed - //iObj.netlist.expNetlist.clear(); - //iObj.netlist.expNetlist.shrink_to_fit(); + // iObj.netlist.expNetlist.clear(); + // iObj.netlist.expNetlist.shrink_to_fit(); if (!tempMinOut) iObj.argMin = tempMinOut; results.xVector.clear(); results.timeAxis.clear(); } -void Simulation::setup_b( - Matrix &mObj, int64_t i, double step, double factor) { +void Simulation::setup_b(Matrix &mObj, int64_t i, double step, double factor) { // Clear b matrix and reset b_.clear(); b_.resize(mObj.rp.size(), 0.0); // Handle jj handle_jj(mObj, i, step, factor); - if(needsTR_) return; + if (needsTR_) return; // Re-factorize the LU if any jj transitions if (needsLU_) { mObj.create_nz(); @@ -186,9 +184,8 @@ void Simulation::setup_b( lu.factorize(true); } else { klu_l_free_numeric(&Numeric_, &Common_); - Numeric_ = klu_l_factor( - &mObj.rp.front(), &mObj.ci.front(), &mObj.nz.front(), - Symbolic_, &Common_); + Numeric_ = klu_l_factor(&mObj.rp.front(), &mObj.ci.front(), + &mObj.nz.front(), Symbolic_, &Common_); } needsLU_ = false; } @@ -206,26 +203,25 @@ void Simulation::setup_b( handle_ps(mObj, i, step, factor); // Handle ccvs handle_ccvs(mObj); - // Handle vccs + // Handle vccs handle_vccs(mObj); // Handle transmission lines handle_tx(mObj, i, step); } - void Simulation::handle_cs(Matrix &mObj, double &step, const int64_t &i) { for (const auto &j : mObj.components.currentsources) { - if(j.indexInfo.nodeConfig_ == NodeConfig::POSGND) { - b_.at(j.indexInfo.posIndex_.value()) -= - (mObj.sourcegen.at(j.sourceIndex_).value(step)); - } else if(j.indexInfo.nodeConfig_ == NodeConfig::GNDNEG) { - b_.at(j.indexInfo.negIndex_.value()) += - (mObj.sourcegen.at(j.sourceIndex_).value(step)); + if (j.indexInfo.nodeConfig_ == NodeConfig::POSGND) { + b_.at(j.indexInfo.posIndex_.value()) -= + (mObj.sourcegen.at(j.sourceIndex_).value(step)); + } else if (j.indexInfo.nodeConfig_ == NodeConfig::GNDNEG) { + b_.at(j.indexInfo.negIndex_.value()) += + (mObj.sourcegen.at(j.sourceIndex_).value(step)); } else { - b_.at(j.indexInfo.posIndex_.value()) -= - (mObj.sourcegen.at(j.sourceIndex_).value(step)); - b_.at(j.indexInfo.negIndex_.value()) += - (mObj.sourcegen.at(j.sourceIndex_).value(step)); + b_.at(j.indexInfo.posIndex_.value()) -= + (mObj.sourcegen.at(j.sourceIndex_).value(step)); + b_.at(j.indexInfo.negIndex_.value()) += + (mObj.sourcegen.at(j.sourceIndex_).value(step)); } } } @@ -234,32 +230,32 @@ void Simulation::handle_resistors(Matrix &mObj, double &step) { for (const auto &j : mObj.components.resistorIndices) { auto &temp = std::get(mObj.components.devices.at(j)); NodeConfig &nc = temp.indexInfo.nodeConfig_; - if(nc == NodeConfig::POSGND) { + if (nc == NodeConfig::POSGND) { if (temp.thermalNoise) { b_.at(temp.indexInfo.posIndex_.value()) -= - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); } temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value())); - } else if(nc == NodeConfig::GNDNEG) { + } else if (nc == NodeConfig::GNDNEG) { if (temp.thermalNoise) { b_.at(temp.indexInfo.negIndex_.value()) += - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); } temp.pn1_ = (-x_.at(temp.indexInfo.negIndex_.value())); } else { if (temp.thermalNoise) { b_.at(temp.indexInfo.posIndex_.value()) -= - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); b_.at(temp.indexInfo.negIndex_.value()) += - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); } - temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - - x_.at(temp.indexInfo.negIndex_.value())); + temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - + x_.at(temp.indexInfo.negIndex_.value())); } if (atyp_ == AnalysisType::Phase) { // 4/3 φp1 - 1/3 φp2 - b_.at(temp.indexInfo.currentIndex_.value()) = - (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; + b_.at(temp.indexInfo.currentIndex_.value()) = + (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; temp.pn4_ = temp.pn3_; temp.pn3_ = temp.pn2_; temp.pn2_ = temp.pn1_; @@ -270,21 +266,20 @@ void Simulation::handle_resistors(Matrix &mObj, double &step) { void Simulation::handle_inductors(Matrix &mObj, double factor) { for (const auto &j : mObj.components.inductorIndices) { auto &temp = std::get(mObj.components.devices.at(j)); - if(atyp_ == AnalysisType::Voltage) { + if (atyp_ == AnalysisType::Voltage) { // -2L/h Ip + L/2h Ip2 - b_.at(temp.indexInfo.currentIndex_.value()) = - -(2.0 * temp.netlistInfo.value_/(stepSize_ * factor)) * - x_.at(temp.indexInfo.currentIndex_.value()) + - ((temp.netlistInfo.value_/(2.0 * (stepSize_ * factor))) * - temp.In2_); + b_.at(temp.indexInfo.currentIndex_.value()) = + -(2.0 * temp.netlistInfo.value_ / (stepSize_ * factor)) * + x_.at(temp.indexInfo.currentIndex_.value()) + + ((temp.netlistInfo.value_ / (2.0 * (stepSize_ * factor))) * + temp.In2_); // -2M/h Im + M/2h Im2 - for(const auto &m : temp.get_mutualInductance()) { - Inductor &mi = - std::get(mObj.components.devices.at(m.first)); - b_.at(temp.indexInfo.currentIndex_.value()) += - (-((2 * m.second) / (stepSize_ * factor)) * - x_.at(mi.indexInfo.currentIndex_.value()) + - (m.second / (2.0 * (stepSize_ * factor))) * mi.In2_); + for (const auto &m : temp.get_mutualInductance()) { + Inductor &mi = std::get(mObj.components.devices.at(m.first)); + b_.at(temp.indexInfo.currentIndex_.value()) += + (-((2 * m.second) / (stepSize_ * factor)) * + x_.at(mi.indexInfo.currentIndex_.value()) + + (m.second / (2.0 * (stepSize_ * factor))) * mi.In2_); } temp.In4_ = temp.In3_; temp.In3_ = temp.In2_; @@ -296,23 +291,23 @@ void Simulation::handle_inductors(Matrix &mObj, double factor) { void Simulation::handle_capacitors(Matrix &mObj) { for (const auto &j : mObj.components.capacitorIndices) { auto &temp = std::get(mObj.components.devices.at(j)); - if(temp.indexInfo.posIndex_ && !temp.indexInfo.negIndex_) { + if (temp.indexInfo.posIndex_ && !temp.indexInfo.negIndex_) { temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value())); - } else if(!temp.indexInfo.posIndex_ && temp.indexInfo.negIndex_) { + } else if (!temp.indexInfo.posIndex_ && temp.indexInfo.negIndex_) { temp.pn1_ = (-x_.at(temp.indexInfo.negIndex_.value())); } else { - temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - - x_.at(temp.indexInfo.negIndex_.value())); + temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - + x_.at(temp.indexInfo.negIndex_.value())); } - if(atyp_ == AnalysisType::Voltage) { + if (atyp_ == AnalysisType::Voltage) { // 4/3 Vp1 - 1/3 Vp2 - b_.at(temp.indexInfo.currentIndex_.value()) = - (4.0/3.0) * temp.pn1_ - (1.0/3.0) * temp.pn2_; + b_.at(temp.indexInfo.currentIndex_.value()) = + (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; } else if (atyp_ == AnalysisType::Phase) { // (8/3)φn-1 - (22/9)φn-2 + (8/9)φn-3 - (1/9)φn-4 - b_.at(temp.indexInfo.currentIndex_.value()) = - (8.0/3.0) * temp.pn1_ - (22.0/9.0) * temp.pn2_ + - (8.0/9.0) * temp.pn3_ - (1.0/9.0) * temp.pn4_; + b_.at(temp.indexInfo.currentIndex_.value()) = + (8.0 / 3.0) * temp.pn1_ - (22.0 / 9.0) * temp.pn2_ + + (8.0 / 9.0) * temp.pn3_ - (1.0 / 9.0) * temp.pn4_; temp.pn7_ = temp.pn6_; temp.pn6_ = temp.pn5_; temp.pn5_ = temp.pn4_; @@ -323,35 +318,35 @@ void Simulation::handle_capacitors(Matrix &mObj) { } } -void Simulation::handle_jj( - Matrix &mObj, int64_t &i, double &step, double factor) { +void Simulation::handle_jj(Matrix &mObj, int64_t &i, double &step, + double factor) { for (const auto &j : mObj.components.junctionIndices) { auto &temp = std::get(mObj.components.devices.at(j)); const auto &model = temp.model_; - if(temp.indexInfo.posIndex_ && !temp.indexInfo.negIndex_) { + if (temp.indexInfo.posIndex_ && !temp.indexInfo.negIndex_) { if (temp.thermalNoise) { b_.at(temp.indexInfo.posIndex_.value()) -= - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); } temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value())); - } else if(!temp.indexInfo.posIndex_ && temp.indexInfo.negIndex_) { + } else if (!temp.indexInfo.posIndex_ && temp.indexInfo.negIndex_) { if (temp.thermalNoise) { b_.at(temp.indexInfo.negIndex_.value()) += - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); } temp.pn1_ = (-x_.at(temp.indexInfo.negIndex_.value())); } else { if (temp.thermalNoise) { b_.at(temp.indexInfo.posIndex_.value()) -= - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); b_.at(temp.indexInfo.negIndex_.value()) += - temp.thermalNoise.value().value(step); + temp.thermalNoise.value().value(step); } - temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - - x_.at(temp.indexInfo.negIndex_.value())); + temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - + x_.at(temp.indexInfo.negIndex_.value())); } - if(i > 0) { - if(atyp_ == AnalysisType::Voltage) { + if (i > 0) { + if (atyp_ == AnalysisType::Voltage) { temp.vn1_ = temp.pn1_; temp.pn1_ = x_.at(temp.variableIndex_); } else if (atyp_ == AnalysisType::Phase) { @@ -360,14 +355,13 @@ void Simulation::handle_jj( } } // Guess voltage (V0) - double v0 = - (5.0/2.0) * temp.vn1_ - 2.0 * temp.vn2_ + (1.0 / 2.0) * temp.vn3_; + double v0 = + (5.0 / 2.0) * temp.vn1_ - 2.0 * temp.vn2_ + (1.0 / 2.0) * temp.vn3_; // Phase guess (P0) - temp.phi0_ = (4.0/3.0) * temp.pn1_ - (1.0/3.0) * temp.pn2_ + - ((1.0 / Constants::SIGMA) * - ((2.0 * (stepSize_)) / 3.0)) * v0; + temp.phi0_ = (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_ + + ((1.0 / Constants::SIGMA) * ((2.0 * (stepSize_)) / 3.0)) * v0; // Ensure timestep is not too large - if ((double)i/(double)simSize_ > 0.01) { + if ((double)i / (double)simSize_ > 0.01) { if (abs(temp.phi0_ - temp.pn1_) > (0.20 * 2 * Constants::PI)) { needsTR_ = true; return; @@ -376,14 +370,14 @@ void Simulation::handle_jj( } } // (hbar / 2 * e) ( -(2 / h) φp1 + (1 / 2h) φp2 ) - if(atyp_ == AnalysisType::Voltage) { - b_.at(temp.variableIndex_) = - (Constants::SIGMA) * (-(2.0 / (stepSize_)) * - temp.pn1_ + (1.0 / (2.0 * (stepSize_))) * temp.pn2_); - // (4 / 3) φp1 - (1/3) φp2 + if (atyp_ == AnalysisType::Voltage) { + b_.at(temp.variableIndex_) = + (Constants::SIGMA) * (-(2.0 / (stepSize_)) * temp.pn1_ + + (1.0 / (2.0 * (stepSize_))) * temp.pn2_); + // (4 / 3) φp1 - (1/3) φp2 } else if (atyp_ == AnalysisType::Phase) { - b_.at(temp.variableIndex_) = - (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; + b_.at(temp.variableIndex_) = + (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; } temp.pn4_ = temp.pn3_; temp.pn3_ = temp.pn2_; @@ -393,70 +387,75 @@ void Simulation::handle_jj( temp.vn4_ = temp.vn3_; temp.vn3_ = temp.vn2_; // Update junction transition - if(model.rtype() == 1) { + if (model.rtype() == 1) { auto testLU = temp.update_value(v0); - if(testLU && !needsLU_) { + if (testLU && !needsLU_) { needsLU_ = true; } } - // sin (φ0 - φ) - double sin_phi = sin(temp.phi0_ - temp.model_.phiOff()); + // Ic * sin (phi * (φ0 - φ)) + double ic_sin_phi = + temp.model_.ic() * + sin(temp.model_.cpr() * (temp.phi0_ - temp.model_.phiOff())); if (!temp.model_.tDep()) { - // -(hR / h + 2RC) * (Ic sin (φ0) - 2C / h Vp1 + C/2h Vp2 + It) + // -(hR / h + 2RC) * (Ic sin (φ0) - 2C / h Vp1 + C/2h Vp2 + It) b_.at(temp.indexInfo.currentIndex_.value()) = - (temp.matrixInfo.nonZeros_.back()) * (temp.model_.ic() * sin_phi - - (((2 * model.c()) / (stepSize_)) * temp.vn1_) + - ((model.c() / (2.0 * (stepSize_))) * temp.vn2_) + - temp.it_); + (temp.matrixInfo.nonZeros_.back()) * + (ic_sin_phi - (((2 * model.c()) / (stepSize_)) * temp.vn1_) + + ((model.c() / (2.0 * (stepSize_))) * temp.vn2_) + temp.it_); } else { - double sin2_half_phi = sin((temp.phi0_ - temp.model_.phiOff()) / 2); + double sin2_half_phi = + sin(temp.model_.cpr() * (temp.phi0_ - temp.model_.phiOff()) / 2); sin2_half_phi = sin2_half_phi * sin2_half_phi; + double sin_phi = + sin(temp.model_.cpr() * (temp.phi0_ - temp.model_.phiOff())); double sqrt_part = sqrt(1 - model.d() * sin2_half_phi); b_.at(temp.indexInfo.currentIndex_.value()) = - // -(hR / h + 2RC) *( - (temp.matrixInfo.nonZeros_.back()) * (( - // (π * Δ / 2 * e * Rn) - ((Constants::PI * temp.del_) - / (2 * Constants::EV * temp.model_.rn())) - // * (sin(φ0 - φ) / √(1 - D * sin²((φ0 - φ) / 2)) - * (sin_phi / sqrt_part) - // * tanh(Δ / (2 * kB * T) * √(1 - D * sin²((φ0 - φ) / 2))) - * tanh(temp.del_ / (2 * Constants::BOLTZMANN * model.t()) - * sqrt_part)) - // - 2C / h Vp1 - - (((2 * model.c()) / stepSize_) * temp.vn1_) - // + C/2h Vp2 - + ((model.c() / (2.0 * stepSize_)) * temp.vn2_) - // + It) - + temp.it_); + // -(hR / h + 2RC) *( + (temp.matrixInfo.nonZeros_.back()) * + (( + // (π * Δ / 2 * e * Rn) + ((Constants::PI * temp.del_) / + (2 * Constants::EV * temp.model_.rn())) + // * (sin(φ0 - φ) / √(1 - D * sin²((φ0 - φ) / 2)) + * (sin_phi / sqrt_part) + // * tanh(Δ / (2 * kB * T) * √(1 - D * sin²((φ0 - φ) / 2))) + * tanh(temp.del_ / (2 * Constants::BOLTZMANN * model.t()) * + sqrt_part)) + // - 2C / h Vp1 + - (((2 * model.c()) / stepSize_) * temp.vn1_) + // + C/2h Vp2 + + ((model.c() / (2.0 * stepSize_)) * temp.vn2_) + // + It) + + temp.it_); } temp.vn2_ = temp.vn1_; } } -void Simulation::handle_vs( - Matrix &mObj, const int64_t &i, double &step, double factor) { +void Simulation::handle_vs(Matrix &mObj, const int64_t &i, double &step, + double factor) { for (const auto &j : mObj.components.vsIndices) { auto &temp = std::get(mObj.components.devices.at(j)); JoSIM::NodeConfig &nc = temp.indexInfo.nodeConfig_; - if(atyp_ == AnalysisType::Voltage) { + if (atyp_ == AnalysisType::Voltage) { // Vn - b_.at(temp.indexInfo.currentIndex_.value()) = - (mObj.sourcegen.at(temp.sourceIndex_).value(step)); + b_.at(temp.indexInfo.currentIndex_.value()) = + (mObj.sourcegen.at(temp.sourceIndex_).value(step)); } else if (atyp_ == AnalysisType::Phase) { - if(nc == NodeConfig::POSGND) { + if (nc == NodeConfig::POSGND) { temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value())); - } else if(nc == NodeConfig::GNDNEG) { + } else if (nc == NodeConfig::GNDNEG) { temp.pn1_ = (-x_.at(temp.indexInfo.negIndex_.value())); } else { - temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - - x_.at(temp.indexInfo.negIndex_.value())); + temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - + x_.at(temp.indexInfo.negIndex_.value())); } // (2e/hbar)(2h/3)Vn + (4/3)φn-1 - (1/3)φn-2 - b_.at(temp.indexInfo.currentIndex_.value()) = - ((2 * stepSize_ * factor) / (3 * Constants::SIGMA)) * - (mObj.sourcegen.at(temp.sourceIndex_).value(step)) + - (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; + b_.at(temp.indexInfo.currentIndex_.value()) = + ((2 * stepSize_ * factor) / (3 * Constants::SIGMA)) * + (mObj.sourcegen.at(temp.sourceIndex_).value(step)) + + (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; temp.pn4_ = temp.pn3_; temp.pn3_ = temp.pn2_; temp.pn2_ = temp.pn1_; @@ -464,35 +463,34 @@ void Simulation::handle_vs( } } -void Simulation::handle_ps( - Matrix &mObj, const int64_t &i, double &step, double factor) { +void Simulation::handle_ps(Matrix &mObj, const int64_t &i, double &step, + double factor) { for (const auto &j : mObj.components.psIndices) { auto &temp = std::get(mObj.components.devices.at(j)); if (atyp_ == AnalysisType::Phase) { // φn - b_.at(temp.indexInfo.currentIndex_.value()) = - (mObj.sourcegen.at(temp.sourceIndex_).value(step)); - } else if(atyp_ == AnalysisType::Voltage) { - if(i == 0) { - b_.at(temp.indexInfo.currentIndex_.value()) = - (Constants::SIGMA / (stepSize_ * factor)) * ((3.0/2.0) * - (mObj.sourcegen.at(temp.sourceIndex_).value(step))); + b_.at(temp.indexInfo.currentIndex_.value()) = + (mObj.sourcegen.at(temp.sourceIndex_).value(step)); + } else if (atyp_ == AnalysisType::Voltage) { + if (i == 0) { + b_.at(temp.indexInfo.currentIndex_.value()) = + (Constants::SIGMA / (stepSize_ * factor)) * + ((3.0 / 2.0) * (mObj.sourcegen.at(temp.sourceIndex_).value(step))); } else if (i == 1) { - b_.at(temp.indexInfo.currentIndex_.value()) = - (Constants::SIGMA / (stepSize_ * factor)) * ((3.0/2.0) * - (mObj.sourcegen.at(temp.sourceIndex_).value(step)) - 2.0 * - (mObj.sourcegen.at( - temp.sourceIndex_).value(step - (stepSize_*factor)))); + b_.at(temp.indexInfo.currentIndex_.value()) = + (Constants::SIGMA / (stepSize_ * factor)) * + ((3.0 / 2.0) * (mObj.sourcegen.at(temp.sourceIndex_).value(step)) - + 2.0 * (mObj.sourcegen.at(temp.sourceIndex_) + .value(step - (stepSize_ * factor)))); } else { - b_.at(temp.indexInfo.currentIndex_.value()) = - (Constants::SIGMA / (stepSize_ * factor)) * ((3.0/2.0) * - (mObj.sourcegen.at(temp.sourceIndex_).value(step)) - 2.0 * - (mObj.sourcegen.at( - temp.sourceIndex_).value(step - (stepSize_*factor))) + 0.5 * - (mObj.sourcegen.at( - temp.sourceIndex_).value(step - (2 * stepSize_*factor)))); + b_.at(temp.indexInfo.currentIndex_.value()) = + (Constants::SIGMA / (stepSize_ * factor)) * + ((3.0 / 2.0) * (mObj.sourcegen.at(temp.sourceIndex_).value(step)) - + 2.0 * (mObj.sourcegen.at(temp.sourceIndex_) + .value(step - (stepSize_ * factor))) + + 0.5 * (mObj.sourcegen.at(temp.sourceIndex_) + .value(step - (2 * stepSize_ * factor)))); } - } } } @@ -501,16 +499,16 @@ void Simulation::handle_ccvs(Matrix &mObj) { for (const auto &j : mObj.components.ccvsIndices) { auto &temp = std::get(mObj.components.devices.at(j)); if (atyp_ == AnalysisType::Phase) { - if(temp.indexInfo.posIndex_ && !temp.indexInfo.negIndex_) { + if (temp.indexInfo.posIndex_ && !temp.indexInfo.negIndex_) { temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value())); - } else if(!temp.indexInfo.posIndex_ && temp.indexInfo.negIndex_) { + } else if (!temp.indexInfo.posIndex_ && temp.indexInfo.negIndex_) { temp.pn1_ = (-x_.at(temp.indexInfo.negIndex_.value())); } else { - temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - - x_.at(temp.indexInfo.negIndex_.value())); + temp.pn1_ = (x_.at(temp.indexInfo.posIndex_.value()) - + x_.at(temp.indexInfo.negIndex_.value())); } - b_.at(temp.indexInfo.currentIndex_.value()) = - (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; + b_.at(temp.indexInfo.currentIndex_.value()) = + (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; temp.pn4_ = temp.pn3_; temp.pn3_ = temp.pn2_; temp.pn2_ = temp.pn1_; @@ -522,16 +520,16 @@ void Simulation::handle_vccs(Matrix &mObj) { for (const auto &j : mObj.components.vccsIndices) { auto &temp = std::get(mObj.components.devices.at(j)); if (atyp_ == AnalysisType::Phase) { - if(temp.posIndex2_ && !temp.negIndex2_) { + if (temp.posIndex2_ && !temp.negIndex2_) { temp.pn1_ = (x_.at(temp.posIndex2_.value())); - } else if(!temp.posIndex2_ && temp.negIndex2_) { + } else if (!temp.posIndex2_ && temp.negIndex2_) { temp.pn1_ = (-x_.at(temp.negIndex2_.value())); } else { - temp.pn1_ = (x_.at(temp.posIndex2_.value()) - - x_.at(temp.negIndex2_.value())); + temp.pn1_ = + (x_.at(temp.posIndex2_.value()) - x_.at(temp.negIndex2_.value())); } - b_.at(temp.indexInfo.currentIndex_.value()) = - (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; + b_.at(temp.indexInfo.currentIndex_.value()) = + (4.0 / 3.0) * temp.pn1_ - (1.0 / 3.0) * temp.pn2_; temp.pn4_ = temp.pn3_; temp.pn3_ = temp.pn2_; temp.pn2_ = temp.pn1_; @@ -539,8 +537,8 @@ void Simulation::handle_vccs(Matrix &mObj) { } } -void Simulation::handle_tx( - Matrix &mObj, const int64_t &i, double &step, double factor) { +void Simulation::handle_tx(Matrix &mObj, const int64_t &i, double &step, + double factor) { for (const auto &j : mObj.components.txIndices) { auto &temp = std::get(mObj.components.devices.at(j)); // Z0 @@ -548,33 +546,32 @@ void Simulation::handle_tx( // Td == k int64_t &k = temp.timestepDelay_; // Shorthands - JoSIM::NodeConfig &nc = temp.indexInfo.nodeConfig_, - &nc2 = temp.nodeConfig2_; - int_o &posInd = temp.indexInfo.posIndex_, - &negInd = temp.indexInfo.negIndex_, - &posInd2 = temp.posIndex2_, - &negInd2 = temp.negIndex2_; + JoSIM::NodeConfig &nc = temp.indexInfo.nodeConfig_, + &nc2 = temp.nodeConfig2_; + int_o &posInd = temp.indexInfo.posIndex_, + &negInd = temp.indexInfo.negIndex_, &posInd2 = temp.posIndex2_, + &negInd2 = temp.negIndex2_; int64_t &curInd = temp.indexInfo.currentIndex_.value(), - &curInd2 = temp.currentIndex2_; - if(atyp_ == AnalysisType::Voltage) { - if(i >= k) { + &curInd2 = temp.currentIndex2_; + if (atyp_ == AnalysisType::Voltage) { + if (i >= k) { // φ1n-k - if(nc == NodeConfig::POSGND) { + if (nc == NodeConfig::POSGND) { temp.nk_1_ = results.xVector.at(posInd.value()).value().at(i - k); - } else if(nc == NodeConfig::GNDNEG) { + } else if (nc == NodeConfig::GNDNEG) { temp.nk_1_ = -results.xVector.at(negInd.value()).value().at(i - k); } else { - temp.nk_1_ = results.xVector.at(posInd.value()).value().at(i - k) - - results.xVector.at(negInd.value()).value().at(i - k); + temp.nk_1_ = results.xVector.at(posInd.value()).value().at(i - k) - + results.xVector.at(negInd.value()).value().at(i - k); } // φ2n-k - if(nc2 == NodeConfig::POSGND) { + if (nc2 == NodeConfig::POSGND) { temp.nk_2_ = results.xVector.at(posInd2.value()).value().at(i - k); - } else if(nc2 == NodeConfig::GNDNEG) { + } else if (nc2 == NodeConfig::GNDNEG) { temp.nk_2_ = -results.xVector.at(negInd2.value()).value().at(i - k); } else { - temp.nk_2_ = results.xVector.at(posInd2.value()).value().at(i - k) - - results.xVector.at(negInd2.value()).value().at(i - k); + temp.nk_2_ = results.xVector.at(posInd2.value()).value().at(i - k) - + results.xVector.at(negInd2.value()).value().at(i - k); } // I1n-k double &I1nk = results.xVector.at(curInd).value().at(i - k); @@ -590,17 +587,17 @@ void Simulation::handle_tx( temp.n2_1_ = temp.n1_1_; temp.n2_2_ = temp.n1_2_; // φ1n-1 - if(nc == NodeConfig::POSGND) { + if (nc == NodeConfig::POSGND) { temp.n1_1_ = (x_.at(posInd.value())); - } else if(nc == NodeConfig::GNDNEG) { + } else if (nc == NodeConfig::GNDNEG) { temp.n1_1_ = (-x_.at(negInd.value())); } else { temp.n1_1_ = (x_.at(posInd.value()) - x_.at(negInd.value())); } // φ2n-1 - if(nc2 == NodeConfig::POSGND) { + if (nc2 == NodeConfig::POSGND) { temp.n1_2_ = (x_.at(posInd2.value())); - } else if(nc2 == NodeConfig::GNDNEG) { + } else if (nc2 == NodeConfig::GNDNEG) { temp.n1_2_ = (-x_.at(negInd2.value())); } else { temp.n1_2_ = (x_.at(posInd2.value()) - x_.at(negInd2.value())); @@ -608,22 +605,22 @@ void Simulation::handle_tx( } if (i >= k) { // φ1n-k - if(nc == NodeConfig::POSGND) { + if (nc == NodeConfig::POSGND) { temp.nk_1_ = results.xVector.at(posInd.value()).value().at(i - k); - } else if(nc == NodeConfig::GNDNEG) { + } else if (nc == NodeConfig::GNDNEG) { temp.nk_1_ = -results.xVector.at(negInd.value()).value().at(i - k); } else { - temp.nk_1_ = results.xVector.at(posInd.value()).value().at(i - k) - - results.xVector.at(negInd.value()).value().at(i - k); + temp.nk_1_ = results.xVector.at(posInd.value()).value().at(i - k) - + results.xVector.at(negInd.value()).value().at(i - k); } // φ2n-k - if(nc2 == NodeConfig::POSGND) { + if (nc2 == NodeConfig::POSGND) { temp.nk_2_ = results.xVector.at(posInd2.value()).value().at(i - k); - } else if(nc2 == NodeConfig::GNDNEG) { + } else if (nc2 == NodeConfig::GNDNEG) { temp.nk_2_ = -results.xVector.at(negInd2.value()).value().at(i - k); } else { - temp.nk_2_ = results.xVector.at(posInd2.value()).value().at(i - k) - - results.xVector.at(negInd2.value()).value().at(i - k); + temp.nk_2_ = results.xVector.at(posInd2.value()).value().at(i - k) - + results.xVector.at(negInd2.value()).value().at(i - k); } // I1n-k double &I1nk = results.xVector.at(curInd).value().at(i - k); @@ -631,112 +628,116 @@ void Simulation::handle_tx( double &I2nk = results.xVector.at(curInd2).value().at(i - k); if (i == k) { // I1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + φ2n-k - b_.at(curInd) = (Z / Constants::SIGMA) * - ((2.0 * stepSize_ * factor) / 3.0) * I2nk + - (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_ + temp.nk_2_; + b_.at(curInd) = (Z / Constants::SIGMA) * + ((2.0 * stepSize_ * factor) / 3.0) * I2nk + + (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_ + + temp.nk_2_; // I2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + φ1n-k - b_.at(curInd2) = (Z / Constants::SIGMA) * - ((2.0 * stepSize_ * factor) / 3.0) * I1nk - + (4.0 / 3.0) * temp.n1_2_ - (1.0 / 3.0) * temp.n2_2_ + temp.nk_1_; + b_.at(curInd2) = (Z / Constants::SIGMA) * + ((2.0 * stepSize_ * factor) / 3.0) * I1nk + + (4.0 / 3.0) * temp.n1_2_ - (1.0 / 3.0) * temp.n2_2_ + + temp.nk_1_; } else if (i == k + 1) { // φ1n-k-1 - if(nc == NodeConfig::POSGND) { - temp.nk1_1_ = results.xVector.at( - posInd.value()).value().at(i - k - 1); - } else if(nc == NodeConfig::GNDNEG) { - temp.nk1_1_ = -results.xVector.at( - negInd.value()).value().at(i - k - 1); + if (nc == NodeConfig::POSGND) { + temp.nk1_1_ = + results.xVector.at(posInd.value()).value().at(i - k - 1); + } else if (nc == NodeConfig::GNDNEG) { + temp.nk1_1_ = + -results.xVector.at(negInd.value()).value().at(i - k - 1); } else { - temp.nk1_1_ = results.xVector.at( - posInd.value()).value().at(i - k - 1) - - results.xVector.at(negInd.value()).value().at(i - k - 1); + temp.nk1_1_ = + results.xVector.at(posInd.value()).value().at(i - k - 1) - + results.xVector.at(negInd.value()).value().at(i - k - 1); } // φ2n-k-1 - if(nc2 == NodeConfig::POSGND) { - temp.nk1_2_ = results.xVector.at( - posInd2.value()).value().at(i - k - 1); - } else if(nc2 == NodeConfig::GNDNEG) { - temp.nk1_2_ = -results.xVector.at( - negInd2.value()).value().at(i - k - 1); + if (nc2 == NodeConfig::POSGND) { + temp.nk1_2_ = + results.xVector.at(posInd2.value()).value().at(i - k - 1); + } else if (nc2 == NodeConfig::GNDNEG) { + temp.nk1_2_ = + -results.xVector.at(negInd2.value()).value().at(i - k - 1); } else { - temp.nk1_2_ = results.xVector.at( - posInd2.value()).value().at(i - k - 1) - - results.xVector.at(negInd2.value()).value().at(i - k - 1); + temp.nk1_2_ = + results.xVector.at(posInd2.value()).value().at(i - k - 1) - + results.xVector.at(negInd2.value()).value().at(i - k - 1); } // I1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + // φ2n-k - (4/3)φ2n-k-1 - b_.at(curInd) = (Z / Constants::SIGMA) * - ((2.0 * stepSize_ * factor) / 3.0) * I2nk + - (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_ + - temp.nk_2_ - (4.0 / 3.0) * temp.nk1_2_; + b_.at(curInd) = (Z / Constants::SIGMA) * + ((2.0 * stepSize_ * factor) / 3.0) * I2nk + + (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_ + + temp.nk_2_ - (4.0 / 3.0) * temp.nk1_2_; // I2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + // φ1n-k - (4/3)φ1n-k-1 - b_.at(curInd2) = (Z / Constants::SIGMA) * - ((2.0 * stepSize_ * factor) / 3.0) * I1nk + - (4.0 / 3.0) * temp.n1_2_ - (1.0 / 3.0) * temp.n2_2_ + - temp.nk_1_ - (4.0 / 3.0) * temp.nk1_1_; + b_.at(curInd2) = (Z / Constants::SIGMA) * + ((2.0 * stepSize_ * factor) / 3.0) * I1nk + + (4.0 / 3.0) * temp.n1_2_ - (1.0 / 3.0) * temp.n2_2_ + + temp.nk_1_ - (4.0 / 3.0) * temp.nk1_1_; } else if (i > k + 1) { // φ1n-k-1 - if(nc == NodeConfig::POSGND) { - temp.nk1_1_ = results.xVector.at( - posInd.value()).value().at(i - k - 1); - } else if(nc == NodeConfig::GNDNEG) { - temp.nk1_1_ = -results.xVector.at( - negInd.value()).value().at(i - k - 1); + if (nc == NodeConfig::POSGND) { + temp.nk1_1_ = + results.xVector.at(posInd.value()).value().at(i - k - 1); + } else if (nc == NodeConfig::GNDNEG) { + temp.nk1_1_ = + -results.xVector.at(negInd.value()).value().at(i - k - 1); } else { - temp.nk1_1_ = results.xVector.at( - posInd.value()).value().at(i - k - 1) - - results.xVector.at(negInd.value()).value().at(i - k - 1); + temp.nk1_1_ = + results.xVector.at(posInd.value()).value().at(i - k - 1) - + results.xVector.at(negInd.value()).value().at(i - k - 1); } // φ2n-k-1 - if(nc2 == NodeConfig::POSGND) { - temp.nk1_2_ = results.xVector.at( - posInd2.value()).value().at(i - k - 1); - } else if(nc2 == NodeConfig::GNDNEG) { - temp.nk1_2_ = -results.xVector.at( - negInd2.value()).value().at(i - k - 1); + if (nc2 == NodeConfig::POSGND) { + temp.nk1_2_ = + results.xVector.at(posInd2.value()).value().at(i - k - 1); + } else if (nc2 == NodeConfig::GNDNEG) { + temp.nk1_2_ = + -results.xVector.at(negInd2.value()).value().at(i - k - 1); } else { - temp.nk1_2_ = results.xVector.at( - posInd2.value()).value().at(i - k - 1) - - results.xVector.at(negInd2.value()).value().at(i - k - 1); + temp.nk1_2_ = + results.xVector.at(posInd2.value()).value().at(i - k - 1) - + results.xVector.at(negInd2.value()).value().at(i - k - 1); } // φ1n-k-2 - if(nc == NodeConfig::POSGND) { - temp.nk2_1_ = results.xVector.at( - posInd.value()).value().at(i - k - 2); - } else if(nc == NodeConfig::GNDNEG) { - temp.nk2_1_ = -results.xVector.at( - negInd.value()).value().at(i - k - 2); + if (nc == NodeConfig::POSGND) { + temp.nk2_1_ = + results.xVector.at(posInd.value()).value().at(i - k - 2); + } else if (nc == NodeConfig::GNDNEG) { + temp.nk2_1_ = + -results.xVector.at(negInd.value()).value().at(i - k - 2); } else { - temp.nk2_1_ = results.xVector.at( - posInd.value()).value().at(i - k - 2) - - results.xVector.at(negInd.value()).value().at(i - k - 2); + temp.nk2_1_ = + results.xVector.at(posInd.value()).value().at(i - k - 2) - + results.xVector.at(negInd.value()).value().at(i - k - 2); } // φ2n-k-2 - if(nc2 == NodeConfig::POSGND) { - temp.nk2_2_ = results.xVector.at( - posInd2.value()).value().at(i - k - 2); - } else if(nc2 == NodeConfig::GNDNEG) { - temp.nk2_2_ = -results.xVector.at( - negInd2.value()).value().at(i - k - 2); + if (nc2 == NodeConfig::POSGND) { + temp.nk2_2_ = + results.xVector.at(posInd2.value()).value().at(i - k - 2); + } else if (nc2 == NodeConfig::GNDNEG) { + temp.nk2_2_ = + -results.xVector.at(negInd2.value()).value().at(i - k - 2); } else { - temp.nk2_2_ = results.xVector.at( - posInd2.value()).value().at(i - k - 2) - - results.xVector.at(negInd2.value()).value().at(i - k - 2); + temp.nk2_2_ = + results.xVector.at(posInd2.value()).value().at(i - k - 2) - + results.xVector.at(negInd2.value()).value().at(i - k - 2); } // I1 = Z(2e/hbar)(2h/3)I2n-k + (4/3)φ1n-1 - (1/3)φ1n-2 + // φ2n-k - (4/3)φ2n-k-1 + (1/3)φ2n-k-2 - b_.at(curInd) = (Z / Constants::SIGMA) * - ((2.0 * stepSize_ * factor) / 3.0) * I2nk + - (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_ + temp.nk_2_ - - (4.0 / 3.0) * temp.nk1_2_ + (1.0 / 3.0) * temp.nk2_2_; + b_.at(curInd) = (Z / Constants::SIGMA) * + ((2.0 * stepSize_ * factor) / 3.0) * I2nk + + (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_ + + temp.nk_2_ - (4.0 / 3.0) * temp.nk1_2_ + + (1.0 / 3.0) * temp.nk2_2_; // I2 = Z(2e/hbar)(2h/3)I1n-k + (4/3)φ2n-1 - (1/3)φ2n-2 + // φ1n-k - (4/3)φ1n-k-1 + (1/3)φ1n-k-2 - b_.at(curInd2) = (Z / Constants::SIGMA) * - ((2.0 * stepSize_ * factor) / 3.0) * I1nk + - (4.0 / 3.0) * temp.n1_2_ - (1.0 / 3.0) * temp.n2_2_ + temp.nk_1_ - - (4.0 / 3.0) * temp.nk1_1_ + (1.0 / 3.0) * temp.nk2_1_; - } + b_.at(curInd2) = (Z / Constants::SIGMA) * + ((2.0 * stepSize_ * factor) / 3.0) * I1nk + + (4.0 / 3.0) * temp.n1_2_ - (1.0 / 3.0) * temp.n2_2_ + + temp.nk_1_ - (4.0 / 3.0) * temp.nk1_1_ + + (1.0 / 3.0) * temp.nk2_1_; + } } else { // I1 = (4/3)φ1n-1 - (1/3)φ1n-2 b_.at(curInd) = (4.0 / 3.0) * temp.n1_1_ - (1.0 / 3.0) * temp.n2_1_; diff --git a/src/Spread.cpp b/src/Spread.cpp index 9ba00138..2623970c 100644 --- a/src/Spread.cpp +++ b/src/Spread.cpp @@ -2,19 +2,20 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Spread.hpp" -#include "JoSIM/Constants.hpp" -#include "JoSIM/Parameters.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" +#include "JoSIM/Parameters.hpp" + using namespace JoSIM; void Spread::get_spreads(Input& iObj) { for (auto& i : iObj.controls) { if (i.front() == "SPREAD") { - for (auto& j : tokens_t(i.begin()+1,i.end())) { + for (auto& j : tokens_t(i.begin() + 1, i.end())) { if (j.at(0) == 'R') { auto t = Misc::tokenize(j, "="); if (t.size() == 2) { @@ -66,14 +67,14 @@ double Spread::spread_value(double value, int64_t type, double spread) { if (spread == 1.0 && gspread_ != 1.0) { spread = gspread_; } - if(spread == 1.0 && gspread_ == 1.0) { + if (spread == 1.0 && gspread_ == 1.0) { return value; } else { std::random_device rd{}; - std::mt19937 gen{ rd() }; + std::mt19937 gen{rd()}; auto min = value * (1 - spread); auto max = value * (1 + spread); - std::normal_distribution<> d(value, (max - min)/6); + std::normal_distribution<> d(value, (max - min) / 6); return d(gen); } return value; diff --git a/src/Transient.cpp b/src/Transient.cpp index 073a3c23..1ac0d579 100644 --- a/src/Transient.cpp +++ b/src/Transient.cpp @@ -2,15 +2,16 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Transient.hpp" -#include "JoSIM/Misc.hpp" #include #include +#include "JoSIM/Misc.hpp" + using namespace JoSIM; -void Transient::identify_simulation( - std::vector& controls, Transient& tObj) { +void Transient::identify_simulation(std::vector& controls, + Transient& tObj) { // Flag to store that a transient simulation was found bool transFound = false; // Loop through all the controls @@ -28,8 +29,8 @@ void Transient::identify_simulation( if (i.size() < 2) { // Complain of invalid transient analysis specification Errors::control_errors( - ControlErrors::TRANS_ERROR, - "Too few parameters: " + Misc::vector_to_string(i)); + ControlErrors::TRANS_ERROR, + "Too few parameters: " + Misc::vector_to_string(i)); // Set the parameters to default values and continue tObj.tstep(0.25E-12); tObj.prstep(1E-12); @@ -66,8 +67,8 @@ void Transient::identify_simulation( // If either the step size or stop time is 0 if (tObj.tstep() == 0 || tObj.tstop() == 0) { // Complain - Errors::control_errors( - ControlErrors::TRANS_ERROR, Misc::vector_to_string(i)); + Errors::control_errors(ControlErrors::TRANS_ERROR, + Misc::vector_to_string(i)); // Set defaults and continue tObj.tstep(0.25E-12); tObj.prstep(tObj.tstep()); @@ -75,10 +76,10 @@ void Transient::identify_simulation( tObj.prstart(0); } //// If user provided time step is larger than 0.25ps junction will fail - //if (tObj.tstep() > 0.25E-12) { - // tObj.tstep(0.25E-12); - //} - // Also if PSTEP is smaller than TSTEP + // if (tObj.tstep() > 0.25E-12) { + // tObj.tstep(0.25E-12); + // } + // Also if PSTEP is smaller than TSTEP if (tObj.tstep() > tObj.prstep()) { // Reduce TSTEP to match PRSTEP tObj.tstep(tObj.prstep()); diff --git a/src/TransmissionLine.cpp b/src/TransmissionLine.cpp index 99b7341a..371c5fa4 100644 --- a/src/TransmissionLine.cpp +++ b/src/TransmissionLine.cpp @@ -2,15 +2,16 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/TransmissionLine.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" -#include -#include #include -#include #include +#include +#include +#include + +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" using namespace JoSIM; @@ -49,15 +50,15 @@ using namespace JoSIM; */ TransmissionLine::TransmissionLine( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, const AnalysisType& at, const double& h, int64_t& bi) { + const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, const AnalysisType& at, const double& h, int64_t& bi) { at_ = at; // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); @@ -70,9 +71,8 @@ TransmissionLine::TransmissionLine( // If impedance keyword is specified but no value given if (s.first.at(i).length() < 4) { // Complain - Errors::invalid_component_errors( - ComponentErrors::INVALID_TX_DEFINED, - Misc::vector_to_string(s.first)); + Errors::invalid_component_errors(ComponentErrors::INVALID_TX_DEFINED, + Misc::vector_to_string(s.first)); } // Set the value (Z0), this should be a value netlistInfo.value_ = parse_param(s.first.at(i).substr(3), pm, s.second); @@ -82,12 +82,12 @@ TransmissionLine::TransmissionLine( // If impedance keyword is specified but no value given if (s.first.at(i).length() < 4) { // Complain - Errors::invalid_component_errors( - ComponentErrors::INVALID_TX_DEFINED, - Misc::vector_to_string(s.first)); + Errors::invalid_component_errors(ComponentErrors::INVALID_TX_DEFINED, + Misc::vector_to_string(s.first)); } // Set the time delay (TD), this should be a value - timestepDelay_ = std::round(parse_param(s.first.at(i).substr(3), pm, s.second) / h); + timestepDelay_ = + std::round(parse_param(s.first.at(i).substr(3), pm, s.second) / h); } } // Set the node configuration type @@ -101,8 +101,8 @@ TransmissionLine::TransmissionLine( // Set the node configuration type for secondary nodes nodeConfig2_ = ncon2.value(); // Set te node indices, using token 4 and 5 - set_secondary_node_indices( - tokens_t(s.first.begin() + 3, s.first.begin() + 5), nm, nc); + set_secondary_node_indices(tokens_t(s.first.begin() + 3, s.first.begin() + 5), + nm, nc); // Set the non zero, column index and row pointer vectors set_matrix_info(); // Append the value to the non zero vector @@ -111,8 +111,8 @@ TransmissionLine::TransmissionLine( matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); } else if (at == AnalysisType::Phase) { // If phase mdoe analysis then append -(2*h/3) * (Z0/σ) - matrixInfo.nonZeros_.emplace_back( - -(2.0 * h / 3.0) * (netlistInfo.value_ / Constants::SIGMA)); + matrixInfo.nonZeros_.emplace_back(-(2.0 * h / 3.0) * + (netlistInfo.value_ / Constants::SIGMA)); } hDepPos_ = matrixInfo.nonZeros_.size() - 1; // Set the non zero, column index and row pointer vectors @@ -123,57 +123,58 @@ TransmissionLine::TransmissionLine( matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); } else if (at == AnalysisType::Phase) { // If phase mdoe analysis then append -(2*h/3) * (Z0/σ) - matrixInfo.nonZeros_.emplace_back( - -(2.0 * h / 3.0) * (netlistInfo.value_ / Constants::SIGMA)); + matrixInfo.nonZeros_.emplace_back(-(2.0 * h / 3.0) * + (netlistInfo.value_ / Constants::SIGMA)); } } -void TransmissionLine::set_secondary_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc) { +void TransmissionLine::set_secondary_node_indices(const tokens_t& t, + const nodemap& nm, + nodeconnections& nc) { // Transmission lines have 4 nodes, this sets the 2nd pair of the 4 switch (nodeConfig2_) { - case NodeConfig::POSGND: - posIndex2_ = nm.at(t.at(0)); - nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(1, currentIndex2_)); - break; - case NodeConfig::GNDNEG: - negIndex2_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(-1, currentIndex2_)); - break; - case NodeConfig::POSNEG: - posIndex2_ = nm.at(t.at(0)); - negIndex2_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(1, currentIndex2_)); - nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(-1, currentIndex2_)); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + posIndex2_ = nm.at(t.at(0)); + nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(1, currentIndex2_)); + break; + case NodeConfig::GNDNEG: + negIndex2_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(-1, currentIndex2_)); + break; + case NodeConfig::POSNEG: + posIndex2_ = nm.at(t.at(0)); + negIndex2_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(0))).emplace_back(std::make_pair(1, currentIndex2_)); + nc.at(nm.at(t.at(1))).emplace_back(std::make_pair(-1, currentIndex2_)); + break; + case NodeConfig::GND: + break; } } void TransmissionLine::set_secondary_matrix_info() { // Tranmission lines have two current branches, this sets the second branch switch (nodeConfig2_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(3); - break; - case NodeConfig::GND: - matrixInfo.rowPointer_.emplace_back(1); - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(3); + break; + case NodeConfig::GND: + matrixInfo.rowPointer_.emplace_back(1); + break; } matrixInfo.columnIndex_.emplace_back(currentIndex2_); } @@ -182,7 +183,7 @@ void TransmissionLine::set_secondary_matrix_info() { void TransmissionLine::update_timestep(const double& factor) { if (at_ == AnalysisType::Phase) { matrixInfo.nonZeros_.at(hDepPos_) = - factor * matrixInfo.nonZeros_.at(hDepPos_); + factor * matrixInfo.nonZeros_.at(hDepPos_); matrixInfo.nonZeros_.back() = factor * matrixInfo.nonZeros_.back(); } } \ No newline at end of file diff --git a/src/VCCS.cpp b/src/VCCS.cpp index 4da71c77..53994f69 100644 --- a/src/VCCS.cpp +++ b/src/VCCS.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/VCCS.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -31,11 +32,11 @@ using namespace JoSIM; ⎣ 0 0 1 -1 -(2e/hbar)(2h/3G)⎦ ⎣Io ⎦ ⎣ (4/3)φn-1 - (1/3)φn-2⎦ */ -VCCS::VCCS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi, const AnalysisType& at, const double& h) { +VCCS::VCCS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi, const AnalysisType& at, + const double& h) { at_ = at; // Set the label netlistInfo.label_ = s.first.at(0); @@ -60,75 +61,75 @@ VCCS::VCCS( // Set initial value of phase node at n-2 pn2_ = 0; // Append the value to the non zero vector - matrixInfo.nonZeros_.emplace_back( - -(1.0 / Constants::SIGMA) * ((2.0 * h) / (3 * netlistInfo.value_))); + matrixInfo.nonZeros_.emplace_back(-(1.0 / Constants::SIGMA) * + ((2.0 * h) / (3 * netlistInfo.value_))); } } -void VCCS::set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc) { - // Set the node indices for the controlled nodes and add column index info +void VCCS::set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc) { + // Set the node indices for the controlled nodes and add column index info switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - indexInfo.posIndex_ = nm.at(t.at(0)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GNDNEG: - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::POSNEG: - indexInfo.posIndex_ = nm.at(t.at(0)); - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + indexInfo.posIndex_ = nm.at(t.at(0)); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GNDNEG: + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::POSNEG: + indexInfo.posIndex_ = nm.at(t.at(0)); + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GND: + break; } // Set the node indices for the controlling nodes switch (nodeConfig2_) { - case NodeConfig::POSGND: - posIndex2_ = nm.at(t.at(2)); - break; - case NodeConfig::GNDNEG: - negIndex2_ = nm.at(t.at(3)); - break; - case NodeConfig::POSNEG: - posIndex2_ = nm.at(t.at(2)); - negIndex2_ = nm.at(t.at(3)); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + posIndex2_ = nm.at(t.at(2)); + break; + case NodeConfig::GNDNEG: + negIndex2_ = nm.at(t.at(3)); + break; + case NodeConfig::POSNEG: + posIndex2_ = nm.at(t.at(2)); + negIndex2_ = nm.at(t.at(3)); + break; + case NodeConfig::GND: + break; } } void VCCS::set_matrix_info() { switch (nodeConfig2_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.emplace_back(3); - break; - case NodeConfig::GND: - matrixInfo.rowPointer_.emplace_back(1); - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.emplace_back(3); + break; + case NodeConfig::GND: + matrixInfo.rowPointer_.emplace_back(1); + break; } matrixInfo.columnIndex_.emplace_back(indexInfo.currentIndex_.value()); } diff --git a/src/VCVS.cpp b/src/VCVS.cpp index b23fc090..903655d5 100644 --- a/src/VCVS.cpp +++ b/src/VCVS.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/VCVS.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -21,11 +22,10 @@ using namespace JoSIM; ⎣-1 1 G -G 0⎦ ⎣Io ⎦ ⎣ 0⎦ */ -VCVS::VCVS( - const std::pair& s, const NodeConfig& ncon, - const std::optional& ncon2, const nodemap& nm, - std::unordered_set& lm, nodeconnections& nc, - const param_map& pm, int64_t& bi) { +VCVS::VCVS(const std::pair& s, const NodeConfig& ncon, + const std::optional& ncon2, const nodemap& nm, + std::unordered_set& lm, nodeconnections& nc, + const param_map& pm, int64_t& bi) { // Set the label netlistInfo.label_ = s.first.at(0); // Add the label to the known labels list @@ -44,89 +44,89 @@ VCVS::VCVS( set_matrix_info(); } -void VCVS::set_node_indices( - const tokens_t& t, const nodemap& nm, nodeconnections& nc) { +void VCVS::set_node_indices(const tokens_t& t, const nodemap& nm, + nodeconnections& nc) { // Set the node indices for the controlling nodes and add column index info switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - indexInfo.posIndex_ = nm.at(t.at(0)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GNDNEG: - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::POSNEG: - indexInfo.posIndex_ = nm.at(t.at(0)); - indexInfo.negIndex_ = nm.at(t.at(1)); - nc.at(nm.at(t.at(0))).emplace_back( - std::make_pair(-1, indexInfo.currentIndex_.value())); - nc.at(nm.at(t.at(1))).emplace_back( - std::make_pair(1, indexInfo.currentIndex_.value())); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + indexInfo.posIndex_ = nm.at(t.at(0)); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GNDNEG: + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::POSNEG: + indexInfo.posIndex_ = nm.at(t.at(0)); + indexInfo.negIndex_ = nm.at(t.at(1)); + nc.at(nm.at(t.at(0))) + .emplace_back(std::make_pair(-1, indexInfo.currentIndex_.value())); + nc.at(nm.at(t.at(1))) + .emplace_back(std::make_pair(1, indexInfo.currentIndex_.value())); + break; + case NodeConfig::GND: + break; } // Set the node indices for the controlled nodes switch (nodeConfig2_) { - case NodeConfig::POSGND: - posIndex2_ = nm.at(t.at(2)); - break; - case NodeConfig::GNDNEG: - negIndex2_ = nm.at(t.at(3)); - break; - case NodeConfig::POSNEG: - posIndex2_ = nm.at(t.at(2)); - negIndex2_ = nm.at(t.at(3)); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + posIndex2_ = nm.at(t.at(2)); + break; + case NodeConfig::GNDNEG: + negIndex2_ = nm.at(t.at(3)); + break; + case NodeConfig::POSNEG: + posIndex2_ = nm.at(t.at(2)); + negIndex2_ = nm.at(t.at(3)); + break; + case NodeConfig::GND: + break; } } void VCVS::set_matrix_info() { switch (indexInfo.nodeConfig_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); - matrixInfo.rowPointer_.emplace_back(1); - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); - matrixInfo.rowPointer_.emplace_back(1); - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(-1); - matrixInfo.nonZeros_.emplace_back(1); - matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); - matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); - matrixInfo.rowPointer_.emplace_back(2); - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); + matrixInfo.rowPointer_.emplace_back(1); + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); + matrixInfo.rowPointer_.emplace_back(1); + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(-1); + matrixInfo.nonZeros_.emplace_back(1); + matrixInfo.columnIndex_.emplace_back(indexInfo.posIndex_.value()); + matrixInfo.columnIndex_.emplace_back(indexInfo.negIndex_.value()); + matrixInfo.rowPointer_.emplace_back(2); + break; + case NodeConfig::GND: + break; } switch (nodeConfig2_) { - case NodeConfig::POSGND: - matrixInfo.nonZeros_.emplace_back(netlistInfo.value_); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.rowPointer_.back()++; - break; - case NodeConfig::GNDNEG: - matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.back()++; - break; - case NodeConfig::POSNEG: - matrixInfo.nonZeros_.emplace_back(netlistInfo.value_); - matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); - matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); - matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); - matrixInfo.rowPointer_.back() += 2; - break; - case NodeConfig::GND: - break; + case NodeConfig::POSGND: + matrixInfo.nonZeros_.emplace_back(netlistInfo.value_); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.rowPointer_.back()++; + break; + case NodeConfig::GNDNEG: + matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.back()++; + break; + case NodeConfig::POSNEG: + matrixInfo.nonZeros_.emplace_back(netlistInfo.value_); + matrixInfo.nonZeros_.emplace_back(-netlistInfo.value_); + matrixInfo.columnIndex_.emplace_back(posIndex2_.value()); + matrixInfo.columnIndex_.emplace_back(negIndex2_.value()); + matrixInfo.rowPointer_.back() += 2; + break; + case NodeConfig::GND: + break; } } \ No newline at end of file diff --git a/src/Verbose.cpp b/src/Verbose.cpp index 2cd62bb3..c6907a4a 100644 --- a/src/Verbose.cpp +++ b/src/Verbose.cpp @@ -2,118 +2,124 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/Verbose.hpp" -#include "JoSIM/Misc.hpp" -#include #include +#include + +#include "JoSIM/Misc.hpp" using namespace JoSIM; -void Verbose::handle_verbosity( - const int64_t& vl, const Input& iObj, const Matrix& mObj) { +void Verbose::handle_verbosity(const int64_t& vl, const Input& iObj, + const Matrix& mObj) { switch (vl) { - case 0: - break; - case 1: - print_circuit_stats(iObj, mObj); - break; - case 2: - print_parameters(iObj); - print_circuit_stats(iObj, mObj); - break; - case 3: - print_expanded_netlist(iObj); - print_parameters(iObj); - print_circuit_stats(iObj, mObj); - break; - default: - Errors::verbosity_errors( - VerbosityErrors::NO_SUCH_LEVEL, std::to_string(vl)); - break; + case 0: + break; + case 1: + print_circuit_stats(iObj, mObj); + break; + case 2: + print_parameters(iObj); + print_circuit_stats(iObj, mObj); + break; + case 3: + print_expanded_netlist(iObj); + print_parameters(iObj); + print_circuit_stats(iObj, mObj); + break; + default: + Errors::verbosity_errors(VerbosityErrors::NO_SUCH_LEVEL, + std::to_string(vl)); + break; } } void Verbose::print_circuit_stats(const Input& iObj, const Matrix& mObj) { std::cout << "Printing circuit statistics:" << std::endl; // Print the total main design lines - std::cout << std::left << std::setw(26) << "Main design lines:" << - iObj.netlist.maindesign.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Main design lines:" << iObj.netlist.maindesign.size() << "\n"; // Print the total number of subcircuits lines - std::cout << std::left << std::setw(26) << "Subcircuit count:" << - iObj.netlist.subcktTotal << "\n"; + std::cout << std::left << std::setw(26) + << "Subcircuit count:" << iObj.netlist.subcktTotal << "\n"; // Print the total component count - std::cout << std::left << std::setw(26) << "Component count:" << - mObj.components.devices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Component count:" << mObj.components.devices.size() << "\n"; // Print the total non-zero count - std::cout << std::left << std::setw(26) << "Non-zero count:" << - mObj.nz.size() << "\n"; + std::cout << std::left << std::setw(26) << "Non-zero count:" << mObj.nz.size() + << "\n"; // Print matrix dimensions - std::cout << std::left << std::setw(26) << "MxN size:" << - mObj.rp.size() << "x" << mObj.rp.size() << "\n"; + std::cout << std::left << std::setw(26) << "MxN size:" << mObj.rp.size() + << "x" << mObj.rp.size() << "\n"; // Print the total jj count if (mObj.components.junctionIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "JJ count:" << - mObj.components.junctionIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "JJ count:" << mObj.components.junctionIndices.size() << "\n"; } // Print the total inductor count if (mObj.components.inductorIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "Inductor count:" << - mObj.components.inductorIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Inductor count:" << mObj.components.inductorIndices.size() + << "\n"; } // Print the total Mutual inductance count if (mObj.components.mutualinductances.size() != 0) { - std::cout << std::left << std::setw(26) << "Mutual inductance count:" << - mObj.components.mutualinductances.size() << "\n"; + std::cout << std::left << std::setw(26) << "Mutual inductance count:" + << mObj.components.mutualinductances.size() << "\n"; } // Print the total resistor count if (mObj.components.resistorIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "Resistor count:" << - mObj.components.resistorIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Resistor count:" << mObj.components.resistorIndices.size() + << "\n"; } // Print the total capacitor count if (mObj.components.capacitorIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "Capacitor count:" << - mObj.components.capacitorIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Capacitor count:" << mObj.components.capacitorIndices.size() + << "\n"; } // Print the total Current source count if (mObj.components.currentsources.size() != 0) { - std::cout << std::left << std::setw(26) << "Current source count:" << - mObj.components.currentsources.size() << "\n"; + std::cout << std::left << std::setw(26) << "Current source count:" + << mObj.components.currentsources.size() << "\n"; } // Print the total Voltage source count if (mObj.components.vsIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "Voltage source count:" << - mObj.components.vsIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Voltage source count:" << mObj.components.vsIndices.size() + << "\n"; } // Print the total Phase source count if (mObj.components.psIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "Phase source count:" << - mObj.components.psIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "Phase source count:" << mObj.components.psIndices.size() + << "\n"; } // Print the total TX line count if (mObj.components.txIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "TX line count:" << - mObj.components.txIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "TX line count:" << mObj.components.txIndices.size() << "\n"; } // Print the total CCCS count if (mObj.components.cccsIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "CCCS count:" << - mObj.components.cccsIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "CCCS count:" << mObj.components.cccsIndices.size() << "\n"; } // Print the total CCVS count if (mObj.components.ccvsIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "CCVS count:" << - mObj.components.ccvsIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "CCVS count:" << mObj.components.ccvsIndices.size() << "\n"; } // Print the total VCCS count if (mObj.components.vccsIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "VCCS count:" << - mObj.components.vccsIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "VCCS count:" << mObj.components.vccsIndices.size() << "\n"; } // Print the total VCVS count if (mObj.components.vcvsIndices.size() != 0) { - std::cout << std::left << std::setw(26) << "VCVS count:" << - mObj.components.vcvsIndices.size() << "\n"; + std::cout << std::left << std::setw(26) + << "VCVS count:" << mObj.components.vcvsIndices.size() << "\n"; } std::cout << std::endl; } @@ -124,10 +130,10 @@ void Verbose::print_parameters(const Input& iObj) { tokens_t sortedParams; for (auto i : iObj.parameters) { std::stringstream value; - value << std::scientific << std::setprecision(6) << - i.second.get_value().value(); - sortedParams.emplace_back(i.first.subcircuit().value_or("") + " : " - + i.first.name() + " = " + value.str()); + value << std::scientific << std::setprecision(6) + << i.second.get_value().value(); + sortedParams.emplace_back(i.first.subcircuit().value_or("") + " : " + + i.first.name() + " = " + value.str()); } std::sort(sortedParams.begin(), sortedParams.end()); for (auto i : sortedParams) { diff --git a/src/VoltageSource.cpp b/src/VoltageSource.cpp index a08572f9..38a5e650 100644 --- a/src/VoltageSource.cpp +++ b/src/VoltageSource.cpp @@ -2,12 +2,13 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/VoltageSource.hpp" -#include "JoSIM/Misc.hpp" -#include "JoSIM/Errors.hpp" -#include "JoSIM/Constants.hpp" #include +#include "JoSIM/Constants.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/Misc.hpp" + using namespace JoSIM; /* @@ -18,14 +19,15 @@ using namespace JoSIM; ⎣ 1 -1 0⎦ ⎣Io⎦ ⎣ 0⎦ */ -VoltageSource::VoltageSource( - const std::pair& s, const NodeConfig& ncon, - const nodemap& nm, std::unordered_set& lm, - nodeconnections& nc, int64_t& bi, const int64_t& si) { +VoltageSource::VoltageSource(const std::pair& s, + const NodeConfig& ncon, const nodemap& nm, + std::unordered_set& lm, + nodeconnections& nc, int64_t& bi, + const int64_t& si) { // Check if the label has already been defined if (lm.count(s.first.at(0)) != 0) { - Errors::invalid_component_errors( - ComponentErrors::DUPLICATE_LABEL, s.first.at(0)); + Errors::invalid_component_errors(ComponentErrors::DUPLICATE_LABEL, + s.first.at(0)); } // Set the label netlistInfo.label_ = s.first.at(0); diff --git a/src/josim.cpp b/src/josim.cpp index 86242f5b..b3c517c3 100644 --- a/src/josim.cpp +++ b/src/josim.cpp @@ -2,23 +2,22 @@ // This code is licensed under MIT license (see LICENSE for details) #include "JoSIM/AnalysisType.hpp" +#include "JoSIM/CliOptions.hpp" +#include "JoSIM/Errors.hpp" +#include "JoSIM/IV.hpp" +#include "JoSIM/Input.hpp" #include "JoSIM/Matrix.hpp" +#include "JoSIM/Model.hpp" +#include "JoSIM/Noise.hpp" #include "JoSIM/Output.hpp" #include "JoSIM/Parameters.hpp" #include "JoSIM/Simulation.hpp" -#include "JoSIM/Verbose.hpp" -#include "JoSIM/CliOptions.hpp" -#include "JoSIM/Input.hpp" -#include "JoSIM/Errors.hpp" #include "JoSIM/Transient.hpp" -#include "JoSIM/Model.hpp" -#include "JoSIM/Noise.hpp" -#include "JoSIM/IV.hpp" +#include "JoSIM/Verbose.hpp" using namespace JoSIM; -int main(int argc, - const char** argv) { +int main(int argc, const char** argv) { try { // Before anything. Display versioning info. CliOptions::version_info(); @@ -34,9 +33,8 @@ int main(int argc, } // Parse any identified models for (const auto& i : iObj.netlist.models) { - Model::parse_model( - std::make_pair(i.second, i.first.second), iObj.netlist.models_new, - iObj.parameters); + Model::parse_model(std::make_pair(i.second, i.first.second), + iObj.netlist.models_new, iObj.parameters); } // Expand nested subcircuits iObj.netlist.expand_subcircuits(); @@ -47,7 +45,7 @@ int main(int argc, // Identify the simulation parameters Transient::identify_simulation(iObj.controls, iObj.transSim); // Add noise (if any) - //Noise::add_noise_sources(iObj); + // Noise::add_noise_sources(iObj); // Create matrix object Matrix mObj; // Create the matrix in csr format @@ -55,10 +53,14 @@ int main(int argc, // Do verbosity Verbose::handle_verbosity(iObj.argVerb, iObj, mObj); //// Dump expanded Netlist since it is no longer needed - //iObj.netlist.expNetlist.clear(); - //iObj.netlist.expNetlist.shrink_to_fit(); - // Find the relevant traces to store + // iObj.netlist.expNetlist.clear(); + // iObj.netlist.expNetlist.shrink_to_fit(); + // Find the relevant traces to store find_relevant_traces(iObj, mObj); + int sum = 0.0; + for (auto& i : mObj.ci) { + sum += i; + } // Create a simulation object Simulation sObj(iObj, mObj); // Create an output object