@@ -509,12 +509,12 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
509
509
# Ensure that we are working with read-only views of numpy arrays
510
510
# Turns Series into arrays so that we don't have to worry about
511
511
# multidimensional broadcasting failing
512
- I , IL , I0 , Rs , Gsh , a = \
512
+ current , IL , I0 , Rs , Gsh , a = \
513
513
np .broadcast_arrays (current , photocurrent , saturation_current ,
514
514
resistance_series , conductance_shunt , nNsVth )
515
515
516
- # Intitalize output V (I might not be float64)
517
- V = np .full_like (I , np .nan , dtype = np .float64 )
516
+ # Intitalize output voltage (current might not be float64)
517
+ voltage = np .full_like (current , np .nan , dtype = np .float64 )
518
518
519
519
# Determine indices where 0 < Gsh requires implicit model solution
520
520
idx_p = 0. < Gsh
@@ -524,17 +524,21 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
524
524
525
525
# Explicit solutions where Gsh=0
526
526
if np .any (idx_z ):
527
- V [idx_z ] = a [idx_z ] * np .log1p ((IL [idx_z ] - I [idx_z ]) / I0 [idx_z ]) - \
528
- I [idx_z ] * Rs [idx_z ]
527
+ voltage [idx_z ] = (
528
+ a [idx_z ] * np .log1p ((IL [idx_z ] - current [idx_z ]) / I0 [idx_z ]) -
529
+ current [idx_z ] * Rs [idx_z ]
530
+ )
529
531
530
532
# Only compute using LambertW if there are cases with Gsh>0
531
533
if np .any (idx_p ):
532
534
# LambertW argument, cannot be float128, may overflow to np.inf
533
535
# overflow is explicitly handled below, so ignore warnings here
534
536
with np .errstate (over = 'ignore' ):
535
- argW = (I0 [idx_p ] / (Gsh [idx_p ] * a [idx_p ]) *
536
- np .exp ((- I [idx_p ] + IL [idx_p ] + I0 [idx_p ]) /
537
- (Gsh [idx_p ] * a [idx_p ])))
537
+ argW = (
538
+ I0 [idx_p ] / (Gsh [idx_p ] * a [idx_p ]) *
539
+ np .exp ((- current [idx_p ] + IL [idx_p ] + I0 [idx_p ]) /
540
+ (Gsh [idx_p ] * a [idx_p ]))
541
+ )
538
542
539
543
# lambertw typically returns complex value with zero imaginary part
540
544
# may overflow to np.inf
@@ -546,10 +550,12 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
546
550
# Only re-compute LambertW if it overflowed
547
551
if np .any (idx_inf ):
548
552
# Calculate using log(argW) in case argW is really big
549
- logargW = (np .log (I0 [idx_p ]) - np .log (Gsh [idx_p ]) -
550
- np .log (a [idx_p ]) +
551
- (- I [idx_p ] + IL [idx_p ] + I0 [idx_p ]) /
552
- (Gsh [idx_p ] * a [idx_p ]))[idx_inf ]
553
+ logargW = (
554
+ np .log (I0 [idx_p ]) - np .log (Gsh [idx_p ]) -
555
+ np .log (a [idx_p ]) +
556
+ (- current [idx_p ] + IL [idx_p ] + I0 [idx_p ]) /
557
+ (Gsh [idx_p ] * a [idx_p ])
558
+ )[idx_inf ]
553
559
554
560
# Three iterations of Newton-Raphson method to solve
555
561
# w+log(w)=logargW. The initial guess is w=logargW. Where direct
@@ -563,13 +569,15 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
563
569
# Eqn. 3 in Jain and Kapoor, 2004
564
570
# V = -I*(Rs + Rsh) + IL*Rsh - a*lambertwterm + I0*Rsh
565
571
# Recast in terms of Gsh=1/Rsh for better numerical stability.
566
- V [idx_p ] = (IL [idx_p ] + I0 [idx_p ] - I [idx_p ]) / Gsh [idx_p ] - \
567
- I [idx_p ] * Rs [idx_p ] - a [idx_p ] * lambertwterm
572
+ voltage [idx_p ] = (
573
+ (IL [idx_p ] + I0 [idx_p ] - current [idx_p ]) / Gsh [idx_p ] -
574
+ current [idx_p ] * Rs [idx_p ] - a [idx_p ] * lambertwterm
575
+ )
568
576
569
577
if output_is_scalar :
570
- return V .item ()
578
+ return voltage .item ()
571
579
else :
572
- return V
580
+ return voltage
573
581
574
582
575
583
def _lambertw_i_from_v (voltage , photocurrent , saturation_current ,
@@ -586,12 +594,12 @@ def _lambertw_i_from_v(voltage, photocurrent, saturation_current,
586
594
# Ensure that we are working with read-only views of numpy arrays
587
595
# Turns Series into arrays so that we don't have to worry about
588
596
# multidimensional broadcasting failing
589
- V , IL , I0 , Rs , Gsh , a = \
597
+ voltage , IL , I0 , Rs , Gsh , a = \
590
598
np .broadcast_arrays (voltage , photocurrent , saturation_current ,
591
599
resistance_series , conductance_shunt , nNsVth )
592
600
593
- # Intitalize output I (V might not be float64)
594
- I = np .full_like (V , np .nan , dtype = np .float64 ) # noqa: E741, N806
601
+ # Intitalize output current (voltage might not be float64)
602
+ current = np .full_like (voltage , np .nan , dtype = np .float64 ) # noqa: E741, N806
595
603
596
604
# Determine indices where 0 < Rs requires implicit model solution
597
605
idx_p = 0. < Rs
@@ -601,17 +609,20 @@ def _lambertw_i_from_v(voltage, photocurrent, saturation_current,
601
609
602
610
# Explicit solutions where Rs=0
603
611
if np .any (idx_z ):
604
- I [idx_z ] = IL [idx_z ] - I0 [idx_z ] * np .expm1 (V [idx_z ] / a [idx_z ]) - \
605
- Gsh [idx_z ] * V [idx_z ]
612
+ current [idx_z ] = (
613
+ IL [idx_z ] - I0 [idx_z ] * np .expm1 (voltage [idx_z ] / a [idx_z ]) -
614
+ Gsh [idx_z ] * voltage [idx_z ]
615
+ )
606
616
607
617
# Only compute using LambertW if there are cases with Rs>0
608
618
# Does NOT handle possibility of overflow, github issue 298
609
619
if np .any (idx_p ):
610
620
# LambertW argument, cannot be float128, may overflow to np.inf
611
- argW = Rs [idx_p ] * I0 [idx_p ] / (
612
- a [idx_p ] * (Rs [idx_p ] * Gsh [idx_p ] + 1. )) * \
613
- np .exp ((Rs [idx_p ] * (IL [idx_p ] + I0 [idx_p ]) + V [idx_p ]) /
614
- (a [idx_p ] * (Rs [idx_p ] * Gsh [idx_p ] + 1. )))
621
+ argW = (
622
+ Rs [idx_p ] * I0 [idx_p ] / (a [idx_p ] * (Rs [idx_p ] * Gsh [idx_p ] + 1. ))
623
+ * np .exp ((Rs [idx_p ] * (IL [idx_p ] + I0 [idx_p ]) + voltage [idx_p ]) /
624
+ (a [idx_p ] * (Rs [idx_p ] * Gsh [idx_p ] + 1. )))
625
+ )
615
626
616
627
# lambertw typically returns complex value with zero imaginary part
617
628
# may overflow to np.inf
@@ -620,14 +631,16 @@ def _lambertw_i_from_v(voltage, photocurrent, saturation_current,
620
631
# Eqn. 2 in Jain and Kapoor, 2004
621
632
# I = -V/(Rs + Rsh) - (a/Rs)*lambertwterm + Rsh*(IL + I0)/(Rs + Rsh)
622
633
# Recast in terms of Gsh=1/Rsh for better numerical stability.
623
- I [idx_p ] = (IL [idx_p ] + I0 [idx_p ] - V [idx_p ] * Gsh [idx_p ]) / \
624
- (Rs [idx_p ] * Gsh [idx_p ] + 1. ) - (
625
- a [idx_p ] / Rs [idx_p ]) * lambertwterm
634
+ current [idx_p ] = (
635
+ (IL [idx_p ] + I0 [idx_p ] - voltage [idx_p ] * Gsh [idx_p ]) /
636
+ (Rs [idx_p ] * Gsh [idx_p ] + 1. ) -
637
+ (a [idx_p ] / Rs [idx_p ]) * lambertwterm
638
+ )
626
639
627
640
if output_is_scalar :
628
- return I .item ()
641
+ return current .item ()
629
642
else :
630
- return I
643
+ return current
631
644
632
645
633
646
def _lambertw (photocurrent , saturation_current , resistance_series ,
@@ -675,8 +688,9 @@ def _pwr_optfcn(df, loc):
675
688
Function to find power from ``i_from_v``.
676
689
'''
677
690
678
- I = _lambertw_i_from_v (df [loc ], df ['photocurrent' ],
679
- df ['saturation_current' ], df ['resistance_series' ],
680
- df ['resistance_shunt' ], df ['nNsVth' ])
691
+ current = _lambertw_i_from_v (df [loc ], df ['photocurrent' ],
692
+ df ['saturation_current' ],
693
+ df ['resistance_series' ],
694
+ df ['resistance_shunt' ], df ['nNsVth' ])
681
695
682
- return I * df [loc ]
696
+ return current * df [loc ]
0 commit comments