Commit 4a9a4191 authored by Aaron Bray's avatar Aaron Bray
Browse files

Encapsulate all tempate implementation as well as eigen usage

parent 443b0796
......@@ -37,6 +37,7 @@
#include <stdexcept>
#include <algorithm>
#include <cmath>
#include <string>
#ifdef _MSC_VER
#include <direct.h>
......@@ -48,6 +49,7 @@
#include <vector>
#include <stack>
#include <map>
#include <set>
#if defined(_MSC_VER)
#include <unordered_map>
......@@ -139,6 +141,7 @@ extern const std::string& eCharge_Name(eCharge m);
// IF YOU ADD A NEW SCALAR TYPE
// PLEASE UPDATE THE METHOD IN SEProperty.cpp
// ALSO DECLARE A TEMPLATE CLASS AT THE BOTTOM OF SESCALAR.CPP
class CCompoundUnit;
......
/* Distributed under the Apache License, Version 2.0.
See accompanying NOTICE file for details.*/
#include "stdafx.h"
#include "circuit/SECircuit.h"
#define ZERO_APPROX 1e-10
#define OPEN_RESISTANCE 1e100
template<CIRCUIT_TEMPLATE>
SECircuit<CIRCUIT_TYPES>::SECircuit(const std::string& name, Logger* logger) : Loggable(logger), m_Name(name)
{
}
template<CIRCUIT_TEMPLATE>
SECircuit<CIRCUIT_TYPES>::~SECircuit()
{
Clear();
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::Clear()
{
for (auto& itr : m_TargetPathMap)
delete itr.second;
for (auto& itr : m_SourcePathMap)
delete itr.second;
for (auto& itr : m_ConnectedPathMap)
delete itr.second;
m_Nodes.clear();
m_Paths.clear();
m_TargetPathMap.clear();
m_SourcePathMap.clear();
m_ConnectedPathMap.clear();
m_ValvePaths.clear();
m_PolarizedElementPaths.clear();
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::StateChange()
{
// Cache target and source paths to save lots of time later
for (auto& itr : m_TargetPathMap)
delete itr.second;
for (auto& itr : m_SourcePathMap)
delete itr.second;
for (auto& itr : m_ConnectedPathMap)
delete itr.second;
m_TargetPathMap.clear();
m_SourcePathMap.clear();
m_ConnectedPathMap.clear();
m_ValvePaths.clear();
m_PolarizedElementPaths.clear();
for (PathType* p : m_Paths)
{
if (!p->HasValidElements())
{
///\error Fatal: Invalid Path in the Circuit.
m_ss << p->GetName() << " has invalid elements";
Fatal(m_ss);
}
//There should never be a NextFlow value set on a path
//Flow sources are defined using NextFlowSource
/* if (p->HasNextFlux())
{
///\error Fatal: Invalid Path in the Circuit.
m_ss << p->GetName() << " has flux and will be ignored and overwritten. Use a flux source.";
Warning(m_ss);
}*/
// Cache what paths are connected to what nodes
NodeType* nTgt = &p->GetTargetNode();
NodeType* nSrc = &p->GetSourceNode();
std::vector<PathType*>* tgtPaths = m_TargetPathMap[nTgt];
std::vector<PathType*>* srcPaths = m_SourcePathMap[nSrc];
std::vector<PathType*>* conSrcPaths = m_ConnectedPathMap[nSrc];
std::vector<PathType*>* conTgtPaths = m_ConnectedPathMap[nTgt];
if (tgtPaths == nullptr)
{
tgtPaths = new std::vector<PathType*>();
m_TargetPathMap[nTgt] = tgtPaths;
}
if (srcPaths == nullptr)
{
srcPaths = new std::vector<PathType*>();
m_SourcePathMap[nSrc] = srcPaths;
}
if (conTgtPaths == nullptr)
{
conTgtPaths = new std::vector<PathType*>();
m_ConnectedPathMap[nTgt] = conTgtPaths;
}
if (conSrcPaths == nullptr)
{
conSrcPaths = new std::vector<PathType*>();
m_ConnectedPathMap[nSrc] = conSrcPaths;
}
//Make sure we didn't accidentally define something twice
if (std::find(m_ConnectedPathMap[nSrc]->begin(), m_ConnectedPathMap[nSrc]->end(), p) != m_ConnectedPathMap[nSrc]->end() ||
std::find(m_ConnectedPathMap[nTgt]->begin(), m_ConnectedPathMap[nTgt]->end(), p) != m_ConnectedPathMap[nTgt]->end())
{
m_ss << p->GetName() << " is defined multiple times.";
Fatal(m_ss);
}
m_TargetPathMap[nTgt]->push_back(p);
m_SourcePathMap[nSrc]->push_back(p);
m_ConnectedPathMap[nSrc]->push_back(p);
m_ConnectedPathMap[nTgt]->push_back(p);
// Cache Valves
if (p->HasNextValve())
m_ValvePaths.push_back(p);
if (p->HasNextPolarizedState())
m_PolarizedElementPaths.push_back(p);
}
if ((m_ValvePaths.size()+m_PolarizedElementPaths.size()) > 64)
{
///\error Fatal: There are too many assumed state options. The Circuit solver can only handle up to 64 Diodes and Polar Elements in a single circuit (i.e. ~1.8e19 possible combinations).
Fatal("There are too many assumed state options. The Circuit solver can only handle up to 64 Diodes and Polar Elements in a single circuit (i.e. ~1.8e19 possible combinations).");
}
}
template<CIRCUIT_TEMPLATE>
std::string SECircuit<CIRCUIT_TYPES>::GetName() const
{
return m_Name;
}
template<CIRCUIT_TEMPLATE>
bool SECircuit<CIRCUIT_TYPES>::HasReferenceNode() const
{
for (NodeType* n : m_Nodes)
{
if (n->IsReferenceNode())
{
return true;
}
}
return false;
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::AddNode(NodeType& node)
{
if (!Contains(this->m_Nodes, node))
this->m_Nodes.push_back(&node);
}
template<CIRCUIT_TEMPLATE>
bool SECircuit<CIRCUIT_TYPES>::HasNode(NodeType& node)
{
return Contains(m_Nodes, node);
}
template<CIRCUIT_TEMPLATE>
bool SECircuit<CIRCUIT_TYPES>::HasNode(const std::string& name)
{
return GetNode(name) != nullptr;
}
template<CIRCUIT_TEMPLATE>
NodeType* SECircuit<CIRCUIT_TYPES>::GetNode(const std::string& name)
{
for (NodeType* n : m_Nodes)
{
if (n->GetName() == name)
return n;
}
return nullptr;
}
template<CIRCUIT_TEMPLATE>
const NodeType* SECircuit<CIRCUIT_TYPES>::GetNode(const std::string& name) const
{
for (NodeType* n : m_Nodes)
{
if (n->GetName() == name)
return n;
}
return nullptr;
}
template<CIRCUIT_TEMPLATE>
const std::vector<NodeType*>& SECircuit<CIRCUIT_TYPES>::GetNodes() const
{
return m_Nodes;
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::RemoveNode(const NodeType& node)
{
size_t i = 0;
for (NodeType* n : m_Nodes)
{
if (n == &node)
{
m_Nodes.erase(m_Nodes.begin() + i);
return;
}
i++;
}
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::RemoveNode(const std::string& name)
{
size_t i = 0;
for (NodeType* n : m_Nodes)
{
if(n->GetName()==name)
{
m_Nodes.erase(m_Nodes.begin()+i);
return;
}
i++;
}
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::AddPath(PathType& path)
{
if (!Contains(m_Paths, path))
m_Paths.push_back(&path);
}
template<CIRCUIT_TEMPLATE>
bool SECircuit<CIRCUIT_TYPES>::HasPath(PathType& path)
{
return Contains(m_Paths, path);
}
template<CIRCUIT_TEMPLATE>
bool SECircuit<CIRCUIT_TYPES>::HasPath(const std::string& name)
{
return GetPath(name) != nullptr;
}
template<CIRCUIT_TEMPLATE>
PathType* SECircuit<CIRCUIT_TYPES>::GetPath(const std::string& name)
{
for (PathType* p : m_Paths)
{
if(p->GetName() == name)
return p;
}
return nullptr;
}
template<CIRCUIT_TEMPLATE>
const PathType* SECircuit<CIRCUIT_TYPES>::GetPath(const std::string& name) const
{
for (PathType* p : m_Paths)
{
if (p->GetName() == name)
return p;
}
return nullptr;
}
template<CIRCUIT_TEMPLATE>
const std::vector<PathType*>& SECircuit<CIRCUIT_TYPES>::GetPaths() const
{
return m_Paths;
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::RemovePath(const PathType& path)
{
size_t i = 0;
for (PathType* p : m_Paths)
{
if(p==&path)
{
m_Paths.erase(m_Paths.begin()+i);
return;
}
i++;
}
}
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::RemovePath(const std::string& name)
{
size_t i = 0;
for (PathType* p : m_Paths)
{
if (p->GetName() == name)
{
m_Paths.erase(m_Paths.begin() + i);
return;
}
i++;
}
}
template<CIRCUIT_TEMPLATE>
const std::vector<PathType*>& SECircuit<CIRCUIT_TYPES>::GetValvePaths()
{
return m_ValvePaths;
}
template<CIRCUIT_TEMPLATE>
const std::vector<PathType*>& SECircuit<CIRCUIT_TYPES>::GetPolarizedElementPaths()
{
return m_PolarizedElementPaths;
}
//--------------------------------------------------------------------------------------------------
/// \brief
/// Returns all target paths for a node
///
/// \param Circuit The circuit in question.
/// \param node Circuit node
///
/// \return Vector of circuit paths
///
/// \details
/// Finds all paths where the input node is the target node. Returns a vector of the paths.
//--------------------------------------------------------------------------------------------------
template<CIRCUIT_TEMPLATE>
const std::vector<PathType*>* SECircuit<CIRCUIT_TYPES>::GetTargetPaths(const NodeType& node) const
{
auto itr = m_TargetPathMap.find(&node);
if (itr == m_TargetPathMap.end())
{
Error("Circuit does not have path information for node",node.GetName());
return nullptr;
}
return itr->second;
}
//--------------------------------------------------------------------------------------------------
/// \brief
/// Returns all source paths for a node
///
/// \param Circuit The circuit in question.
/// \param node Circuit node
///
/// \return Vector of circuit paths
///
/// \details
/// Finds all paths where the input node is the source node. Returns a vector of the paths.
//--------------------------------------------------------------------------------------------------
template<CIRCUIT_TEMPLATE>
const std::vector<PathType*>* SECircuit<CIRCUIT_TYPES>::GetSourcePaths(const NodeType& node) const
{
auto itr = m_SourcePathMap.find(&node);
if (itr == m_SourcePathMap.end())
{
Error("Circuit does not have path information for node", node.GetName());
return nullptr;
}
return itr->second;
}
//--------------------------------------------------------------------------------------------------
/// \brief
/// Returns all source paths for a node
///
/// \param Circuit The circuit in question.
/// \param node Circuit node
///
/// \return Vector of circuit paths
///
/// \details
/// Finds all paths where the input node is the source or target node. Returns a vector of the paths.
//--------------------------------------------------------------------------------------------------
template<CIRCUIT_TEMPLATE>
const std::vector<PathType*>* SECircuit<CIRCUIT_TYPES>::GetConnectedPaths(const NodeType& node) const
{
auto itr = m_ConnectedPathMap.find(&node);
if (itr == m_ConnectedPathMap.end())
{
Error("Circuit does not have path information for node", node.GetName());
return nullptr;
}
return itr->second;
}
//--------------------------------------------------------------------------------------------------
/// \brief
/// Set all Current and Next values to the Baseline values for all Elements.
//--------------------------------------------------------------------------------------------------
template<CIRCUIT_TEMPLATE>
void SECircuit<CIRCUIT_TYPES>::SetNextAndCurrentFromBaselines()
{
for(PathType* p : m_Paths)
{
if (p->HasResistanceBaseline())
{
p->GetResistance().Copy(p->GetResistanceBaseline());
p->GetNextResistance().Copy(p->GetResistanceBaseline());
}
if (p->HasCapacitanceBaseline())
{
p->GetCapacitance().Copy(p->GetCapacitanceBaseline());
p->GetNextCapacitance().Copy(p->GetCapacitanceBaseline());
}
if (p->HasInductanceBaseline())
{
p->GetInductance().Copy(p->GetInductanceBaseline());
p->GetNextInductance().Copy(p->GetInductanceBaseline());
}
if (p->HasFluxSourceBaseline())
{
p->GetFluxSource().Copy(p->GetFluxSourceBaseline());
p->GetNextFluxSource().Copy(p->GetFluxSourceBaseline());
}
if (p->HasPotentialSourceBaseline())
{
p->GetPotentialSource().Copy(p->GetPotentialSourceBaseline());
p->GetNextPotentialSource().Copy(p->GetPotentialSourceBaseline());
}
if (p->HasSwitch())
p->SetNextSwitch(p->GetSwitch());
if (p->HasValve())
p->SetNextValve(p->GetValve());
}
for (NodeType* n : m_Nodes)
{
if (n->HasQuantityBaseline())
{
n->GetQuantity().Copy(n->GetQuantityBaseline());
n->GetNextQuantity().Copy(n->GetQuantityBaseline());
}
}
}
#include "circuit/electrical/SEElectricalCircuit.h"
template class SECircuit< SEElectricalCircuitNode, SEElectricalCircuitPath>;
#include "circuit/fluid/SEFluidCircuit.h"
template class SECircuit< SEFluidCircuitNode, SEFluidCircuitPath>;
#include "circuit/thermal/SEThermalCircuit.h"
template class SECircuit< SEThermalCircuitNode, SEThermalCircuitPath>;
\ No newline at end of file
......@@ -65,5 +65,4 @@ protected:
std::vector<PathType*> m_ValvePaths;
std::vector<PathType*> m_PolarizedElementPaths;
};
#include "circuit/SECircuit.inl"
\ No newline at end of file
};
\ No newline at end of file
This diff is collapsed.
......@@ -2,13 +2,13 @@
See accompanying NOTICE file for details.*/
#pragma once
#include "Eigen/Core"
#include "utils/SmartEnum.h"
#include <set>
#define CIRCUIT_CALCULATOR_TEMPLATE typename CircuitType, typename NodeType, typename PathType, typename CapacitanceUnit, typename FluxUnit, typename InductanceUnit, typename PotentialUnit, typename QuantityUnit, typename ResistanceUnit
#define CIRCUIT_CALCULATOR_TYPES CircuitType,NodeType,PathType,CapacitanceUnit,FluxUnit,InductanceUnit,PotentialUnit,QuantityUnit,ResistanceUnit
class eigen; // Encapsulate eigen in pimpl pattern
// These are the Eigen Solvers we can use for solving our circuits
struct CDM_DECL EigenCircuitSolver
{
......@@ -45,12 +45,8 @@ protected:
virtual void PopulateAMatrix(NodeType& nKCL, PathType& p, double dMultiplier, bool hasPotentialSource = false);
// These are all transient and cleared/set at the start of the process call
std::stringstream m_ss;
//Ax=b
Eigen::MatrixXd m_AMatrix; //A
Eigen::VectorXd m_xVector; //x
Eigen::VectorXd m_bVector; //b
std::stringstream m_ss;
double m_dT_s;
double m_currentTime_s;
double m_refPotential;
......@@ -65,5 +61,7 @@ protected:
const PotentialUnit &m_PotentialUnit;
const QuantityUnit &m_QuantityUnit;
const ResistanceUnit &m_ResistanceUnit;
};
#include "circuit/SECircuitCalculator.inl"
\ No newline at end of file
private:
eigen* _eigen;
};
\ No newline at end of file
This diff is collapsed.
......@@ -218,3 +218,140 @@ void SECircuitManager::DeleteThermalCircuit(const std:
bool SECircuitManager::HasThermalCircuit(const std::string& name) const { return HasCircuit<THERMAL_LEDGER_TYPES>(name, m_ThermalLedger); }
SEThermalCircuit* SECircuitManager::GetThermalCircuit(const std::string& name) { return GetCircuit<THERMAL_LEDGER_TYPES>(name, m_ThermalLedger); }
const SEThermalCircuit* SECircuitManager::GetThermalCircuit(const std::string& name) const { return GetCircuit<THERMAL_LEDGER_TYPES>(name, m_ThermalLedger); }
template<CIRCUIT_LEDGER_TEMPLATE> NodeType& SECircuitManager::CreateNode(const std::string& name, SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger)
{
NodeType* node = ledger.nodes[name];
if (node != nullptr)
{
Error("Node already exists with name " + name + ", not creating a new node, returning the existing node");
return *node;
}
node = new NodeType(name, GetLogger());
ledger.nodes[name] = node;
return *node;
}
template<CIRCUIT_LEDGER_TEMPLATE> void SECircuitManager::DeleteNode(const std::string& name, SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger)
{
PathType* path;
NodeType* node = GetNode(name, ledger);
if (node == nullptr)
return;
// Remove this node from any circuits
for (auto citr : ledger.circuits)
citr.second->RemoveNode(*node);
// Search the paths and delete any paths that has this node
// And remove those paths from any circuits
for (auto pitr = ledger.paths.begin(); pitr != ledger.paths.end();)
{
if (pitr->second->GetSourceNode().GetName() == name)
{
path = pitr->second;
ledger.paths.erase(pitr++);
for (auto citr : ledger.circuits)
citr.second->RemovePath(*path);
SAFE_DELETE(path);
}
else
pitr++;
}
ledger.nodes.erase(node->GetName());
SAFE_DELETE(node);
}
template<CIRCUIT_LEDGER_TEMPLATE> bool SECircuitManager::HasNode(const std::string& name, const SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger) const
{
return ledger.nodes.find(name) != ledger.nodes.end();
}
template<CIRCUIT_LEDGER_TEMPLATE> NodeType* SECircuitManager::GetNode(const std::string& name, SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger)
{
auto itr = ledger.nodes.find(name);
if (itr != ledger.nodes.end())
return itr->second;
return nullptr;
}
template<CIRCUIT_LEDGER_TEMPLATE> const NodeType* SECircuitManager::GetNode(const std::string& name, const SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger) const
{
auto itr = ledger.nodes.find(name);
if (itr != ledger.nodes.end())
return itr->second;
return nullptr;
}
template<CIRCUIT_LEDGER_TEMPLATE> PathType& SECircuitManager::CreatePath(NodeType& src, NodeType& tgt, const std::string& name, SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger)
{
PathType* path = ledger.paths[name];
if (path != nullptr)
{
Error(" path already exists with name " + name + ", not creating a new path, returning the existing path");
return *path;
}
path = new PathType(src, tgt, name);
ledger.paths[name] = path;
return *path;
}
template<CIRCUIT_LEDGER_TEMPLATE> void SECircuitManager::DeletePath(const std::string& name, SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger)
{
PathType* path = GetPath(name, ledger);
if (path == nullptr)
return;
ledger.paths.erase(name);
for (auto itr : ledger.circuits)
itr.second->RemovePath(*path);
SAFE_DELETE(path);
}
template<CIRCUIT_LEDGER_TEMPLATE> bool SECircuitManager::HasPath(const std::string& name, const SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger) const
{
return ledger.paths.find(name) != ledger.paths.end();
}
template<CIRCUIT_LEDGER_TEMPLATE> PathType* SECircuitManager::GetPath(const std::string& name, SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger)
{
auto itr = ledger.paths.find(name);
if (itr != ledger.paths.end())
return itr->second;
return nullptr;
}
template<CIRCUIT_LEDGER_TEMPLATE> const PathType* SECircuitManager::GetPath(const std::string& name, const SECircuitLedger<CIRCUIT_LEDGER_TYPES>& ledger) const
{
auto itr = ledger.paths.find(name);
if (itr != ledger.paths.end())
return itr->second;