I think I have found a future performance show stopper in the way
Pycircuit calculates the charge/flow and current residues (q, i) and
their Jacobians (C, G).
Today, every call to the i,q,C,G methods creates and returns a new
array. And in Python creating new objects is quite an expensive
operation. It becomes even worse in a hierarchical circuit where new
objects will be created for each visited instance. Another problem is
that for more complex models with lots of if-statements etc the
program flow will be duplicated in i,q,C and G.
There were 2 reasons for not doing it like every other simulator does
it, having one big matrix for the full circuit and let the subcircuits
stamp into it at their nodes.
First I wanted circuit objects to be stand-alone entities without
having to be aware of that they were part of a bigger hierarchy with
pointers into the big matrix.
The second reason was isolation. Stamping into the big matrix allows
subcircuits to mess with elements that doesn't belongs to them.
One possible solution that wouldn't have these downsides would be to
create a new class (CircuitMatrices?) that stores the matrices and
vectors for the full circuit. This class is aware of the structure of
the circuit and knows the mapping of local nodes of each element to
the full circuit. Next, a new method to the Circuit class which
updates the i,q,C,G arrays is created. The new method takes an
instance of CircuitMatrices as its argument and asks it for the input
voltage
and then calls different methods of it to stamp the i,q, C and G
vectors/matrices. It also takes an instance identifier that is passed
to the calls to CircuitMatrices. That way the element doesn't need to
know anything about it's place in the hierarchy.
Example:
class CircuitMatrices:
def get_input(self, instance_ref, nodenum1, nodenum2)
def stampG(self, instance_ref, nodenum1, nodenum2, value)
def stampC(self, instance_ref, nodenum1, nodenum2, value)
def stampi(self, instance_ref, nodenum1, nodenum2, value)
def stampq(self, instance_ref, nodenum1, nodenum2, value)
class Circuit:
def create_circuitmatrices(self):
"""Create a CircuitMatrices object"""
def update_matrices(self, instance_ref, cm_instance):
"""Update matrices"""
class R:
def update_matrices(self, instance_ref, cm_instance):
cm_instance.stampi(instance_ref, 0, 1, 1/self.ipar.R * )
Ett sätt att komma runt alla dessa problem är att skapa en ny klass
som lagrar i,q vektorerna och Q,C matriserna för hela kretsen man vill
simulera. Sen skapar men en ny en load-metod till Circuit klassen som
uppdaterar alla matriser/ uppdatera vektorerna/matriserna på liknande
sätt som man gör i BSMATRIX i gnucap uppdaterar alla fyra element
samtidigt av en enport.
På det sättet har man bara en matris som man uppdaterar utan att
behöva skapa nya matriser för varje anrop till Q, C, i, q. Man lagrar
inte heller några matriser i Circuitklassen. Så laddningsmetoden tar
ett sådant argumentet
Example:
vin = cm_instance.get_input(instance_ref, 0, 1)
cm_instance.stampi(instance_ref, 0, 1, 1/self.ipar.R * vin)
cm_instance.stampG(instance_ref, 0, 1, 1/self.ipar.R)
For backwards compatibility one can keep the i,q,G,C methods which
will then create a CircuitMatrices object and call update_matrices and
return one of the matrices.
It's not as clean and straightforward as before but will not have the
bottleneck with the creation of Python objects.
/Henrik
I pressed the send button to fast by mistake.
/Henrik
2009/7/5 henrik johansson <henj...@gmail.com>:
> One possible solution that wouldn't have these downsides would be to
> create a new class (CircuitMatrices?) that stores the matrices and
> vectors for the full circuit. This class is aware of the structure of
> the circuit and knows the mapping of local nodes of each element to
> the full circuit. Next, a new method to the Circuit class which
> updates the i,q,C,G arrays is created. The new method takes an
> instance of CircuitMatrices as its argument and asks it for the input
> voltage
> and then calls different methods of it to stamp the i,q, C and G
> vectors/matrices. It also takes an instance identifier that is passed
> to the calls to CircuitMatrices. That way the element doesn't need to
> know anything about it's place in the hierarchy.
I will have to look more on your detailed description, but creating
once and then updating is more attractive performance wise. Probably
necessary. I agree that it is good not to let devices stamp directly
into the large matrix. Having a separate 'stamping mechanism' that
uses the updated matrices seems like a good idea.
/Joacim