@@ -36,7 +36,7 @@ def __init__(self, mesh):
36
36
super ().__init__ (mesh )
37
37
38
38
# there is no way to set this at the moment
39
- self .extrapolation = "linear "
39
+ self .extrapolation = "quadratic "
40
40
41
41
# add npts_for_broadcast to mesh domains for this particular discretisation
42
42
for dom in mesh .keys ():
@@ -576,9 +576,9 @@ def add_ghost_nodes(self, symbol, discretised_symbol, bcs):
576
576
577
577
return pybamm .Matrix (matrix ) @ discretised_symbol + bcs_vector
578
578
579
- def boundary_value_or_flux (self , symbol , discretised_child ):
579
+ def boundary_value_or_flux (self , symbol , discretised_child , bcs = None ):
580
580
"""
581
- Uses linear extrapolation to get the boundary value or flux of a variable in the
581
+ Uses extrapolation to get the boundary value or flux of a variable in the
582
582
Finite Volume Method.
583
583
584
584
See :meth:`pybamm.SpatialMethod.boundary_value`
@@ -590,9 +590,14 @@ def boundary_value_or_flux(self, symbol, discretised_child):
590
590
prim_pts = submesh_list [0 ].npts
591
591
sec_pts = len (submesh_list )
592
592
593
+ if not bcs :
594
+ bcs = {}
595
+
593
596
# Create submatrix to compute boundary values or fluxes
594
597
if isinstance (symbol , pybamm .BoundaryValue ):
595
598
599
+ # Derivation of extrapolation formula can be found at:
600
+ # https://github.com/Scottmar93/extrapolation-coefficents/tree/master
596
601
nodes = submesh_list [0 ].nodes
597
602
edges = submesh_list [0 ].edges
598
603
@@ -604,85 +609,140 @@ def boundary_value_or_flux(self, symbol, discretised_child):
604
609
dxNm1 = submesh_list [0 ].d_nodes [- 1 ]
605
610
dxNm2 = submesh_list [0 ].d_nodes [- 2 ]
606
611
612
+ child = symbol .child
613
+
607
614
if symbol .side == "left" :
608
615
609
616
if self .extrapolation == "linear" :
610
617
# to find value at x* use formula:
611
618
# f(x*) = f_1 - (dx0 / dx1) (f_2 - f_1)
612
- # where
613
- # dx0 is distance between edge and first node
614
- # dx1 is distance between first and second nodes
615
619
616
- sub_matrix = csr_matrix (
617
- ([1 + (dx0 / dx1 ), - (dx0 / dx1 )], ([0 , 0 ], [0 , 1 ])),
618
- shape = (1 , prim_pts ),
619
- )
620
+ if pybamm .has_bc_condition_of_form (
621
+ child , symbol .side , bcs , "Neumann"
622
+ ):
623
+ sub_matrix = csr_matrix (([1 ], ([0 ], [0 ])), shape = (1 , prim_pts ),)
624
+
625
+ additive = - dx0 * bcs [child .id ][symbol .side ][0 ]
626
+
627
+ else :
628
+ sub_matrix = csr_matrix (
629
+ ([1 + (dx0 / dx1 ), - (dx0 / dx1 )], ([0 , 0 ], [0 , 1 ])),
630
+ shape = (1 , prim_pts ),
631
+ )
632
+ additive = pybamm .Scalar (0 )
633
+
620
634
elif self .extrapolation == "quadratic" :
621
- # to find value at x* use formula:
622
- # see mathematica notebook at:
623
- # https://github.com/Scottmar93/extrapolation-coefficents/tree/master
624
- # f(x*) = a f_1 + b f_2 + c f_3
625
635
626
- a = (dx0 + dx1 ) * (dx0 + dx1 + dx2 ) / (dx1 * (dx1 + dx2 ))
627
- b = - dx0 * (dx0 + dx1 + dx2 ) / (dx1 * dx2 )
628
- c = dx0 * (dx0 + dx1 ) / (dx2 * (dx1 + dx2 ))
636
+ if pybamm .has_bc_condition_of_form (
637
+ child , symbol .side , bcs , "Neumann"
638
+ ):
639
+ a = (dx0 + dx1 ) ** 2 / (dx1 * (2 * dx0 + dx1 ))
640
+ b = - (dx0 ** 2 ) / (2 * dx0 * dx1 + dx1 ** 2 )
641
+ alpha = - (dx0 * (dx0 + dx1 )) / (2 * dx0 + dx1 )
629
642
630
- sub_matrix = csr_matrix (
631
- ([a , b , c ], ([0 , 0 , 0 ], [0 , 1 , 2 ])), shape = (1 , prim_pts ),
632
- )
643
+ sub_matrix = csr_matrix (
644
+ ([a , b ], ([0 , 0 ], [0 , 1 ])), shape = (1 , prim_pts ),
645
+ )
646
+ additive = alpha * bcs [child .id ][symbol .side ][0 ]
647
+
648
+ else :
649
+ a = (dx0 + dx1 ) * (dx0 + dx1 + dx2 ) / (dx1 * (dx1 + dx2 ))
650
+ b = - dx0 * (dx0 + dx1 + dx2 ) / (dx1 * dx2 )
651
+ c = dx0 * (dx0 + dx1 ) / (dx2 * (dx1 + dx2 ))
652
+
653
+ sub_matrix = csr_matrix (
654
+ ([a , b , c ], ([0 , 0 , 0 ], [0 , 1 , 2 ])), shape = (1 , prim_pts ),
655
+ )
656
+
657
+ additive = pybamm .Scalar (0 )
633
658
else :
634
659
raise NotImplementedError
635
660
636
661
elif symbol .side == "right" :
637
662
638
663
if self .extrapolation == "linear" :
639
- # to find value at x* use formula:
640
- # f(x*) = f_N - (dxN / dxNm1) (f_N - f_Nm1)
641
- # where
642
- # dxN is distance between edge and last node
643
- # dxNm1 is distance between second lase and last nodes
644
664
645
- sub_matrix = csr_matrix (
646
- (
647
- [- (dxN / dxNm1 ), 1 + (dxN / dxNm1 )],
648
- ([0 , 0 ], [prim_pts - 2 , prim_pts - 1 ]),
649
- ),
650
- shape = (1 , prim_pts ),
651
- )
665
+ if pybamm .has_bc_condition_of_form (
666
+ child , symbol .side , bcs , "Neumann"
667
+ ):
668
+ # use formula:
669
+ # f(x*) = fN + dxN * f'(x*)
670
+ sub_matrix = csr_matrix (
671
+ ([1 ], ([0 ], [prim_pts - 1 ]),), shape = (1 , prim_pts ),
672
+ )
673
+ additive = dxN * bcs [child .id ][symbol .side ][0 ]
674
+
675
+ elif pybamm .has_bc_condition_of_form (
676
+ child , symbol .side , bcs , "Dirichlet"
677
+ ):
678
+ # just use the value from the bc: f(x*)
679
+ sub_matrix = csr_matrix ((1 , prim_pts ))
680
+ additive = bcs [child .id ][symbol .side ][0 ]
681
+
682
+ else :
683
+ # to find value at x* use formula:
684
+ # f(x*) = f_N - (dxN / dxNm1) (f_N - f_Nm1)
685
+ sub_matrix = csr_matrix (
686
+ (
687
+ [- (dxN / dxNm1 ), 1 + (dxN / dxNm1 )],
688
+ ([0 , 0 ], [prim_pts - 2 , prim_pts - 1 ]),
689
+ ),
690
+ shape = (1 , prim_pts ),
691
+ )
692
+ additive = pybamm .Scalar (0 )
652
693
elif self .extrapolation == "quadratic" :
653
- # to find value at x* use formula:
654
- # see mathematica notebook at:
655
- # https://github.com/Scottmar93/extrapolation-coefficents/tree/master
656
- # f(x*) = a f_N + b f_Nm1 + c f_Nm2
657
-
658
- a = (
659
- (dxN + dxNm1 )
660
- * (dxN + dxNm1 + dxNm2 )
661
- / (dxNm1 * (dxNm1 + dxNm2 ))
662
- )
663
- b = - dxN * (dxN + dxNm1 + dxNm2 ) / (dxNm1 * dxNm2 )
664
- c = dxN * (dxN + dxNm1 ) / (dxNm2 * (dxNm1 + dxNm2 ))
665
694
666
- sub_matrix = csr_matrix (
667
- (
668
- [c , b , a ],
669
- ([0 , 0 , 0 ], [prim_pts - 3 , prim_pts - 2 , prim_pts - 1 ]),
670
- ),
671
- shape = (1 , prim_pts ),
672
- )
695
+ if pybamm .has_bc_condition_of_form (
696
+ child , symbol .side , bcs , "Neumann"
697
+ ):
698
+ a = (dxN + dxNm1 ) ** 2 / (dxNm1 * (2 * dxN + dxNm1 ))
699
+ b = - (dxN ** 2 ) / (2 * dxN * dxNm1 + dxNm1 ** 2 )
700
+ alpha = dxN * (dxN + dxNm1 ) / (2 * dxN + dxNm1 )
701
+ sub_matrix = csr_matrix (
702
+ ([b , a ], ([0 , 0 ], [prim_pts - 2 , prim_pts - 1 ]),),
703
+ shape = (1 , prim_pts ),
704
+ )
705
+
706
+ additive = alpha * bcs [child .id ][symbol .side ][0 ]
707
+
708
+ else :
709
+ a = (
710
+ (dxN + dxNm1 )
711
+ * (dxN + dxNm1 + dxNm2 )
712
+ / (dxNm1 * (dxNm1 + dxNm2 ))
713
+ )
714
+ b = - dxN * (dxN + dxNm1 + dxNm2 ) / (dxNm1 * dxNm2 )
715
+ c = dxN * (dxN + dxNm1 ) / (dxNm2 * (dxNm1 + dxNm2 ))
716
+
717
+ sub_matrix = csr_matrix (
718
+ (
719
+ [c , b , a ],
720
+ ([0 , 0 , 0 ], [prim_pts - 3 , prim_pts - 2 , prim_pts - 1 ]),
721
+ ),
722
+ shape = (1 , prim_pts ),
723
+ )
724
+ additive = pybamm .Scalar (0 )
673
725
else :
674
726
raise NotImplementedError
675
727
676
728
elif isinstance (symbol , pybamm .BoundaryGradient ):
677
729
if symbol .side == "left" :
678
- # use formula:
679
- # f'(x*) = (f_2 - f_1) / dx1
680
- # where dx1 = x_2 - x_1
681
730
682
731
if self .extrapolation == "linear" :
683
- sub_matrix = (1 / dx1 ) * csr_matrix (
684
- ([- 1 , 1 ], ([0 , 0 ], [0 , 1 ])), shape = (1 , prim_pts )
685
- )
732
+
733
+ if pybamm .has_bc_condition_of_form (
734
+ child , symbol .side , bcs , "Neumann"
735
+ ):
736
+ # just use the value from the bc: f'(x*)
737
+ sub_matrix = csr_matrix ((1 , prim_pts ))
738
+ additive = bcs [child .id ][symbol .side ][0 ]
739
+ else :
740
+ # use formula:
741
+ # f'(x*) = (f_2 - f_1) / dx1
742
+ sub_matrix = (1 / dx1 ) * csr_matrix (
743
+ ([- 1 , 1 ], ([0 , 0 ], [0 , 1 ])), shape = (1 , prim_pts )
744
+ )
745
+ additive = pybamm .Scalar (0 )
686
746
elif self .extrapolation == "quadratic" :
687
747
688
748
a = - (2 * dx0 + 2 * dx1 + dx2 ) / (dx1 ** 2 + dx1 * dx2 )
@@ -692,17 +752,28 @@ def boundary_value_or_flux(self, symbol, discretised_child):
692
752
sub_matrix = csr_matrix (
693
753
([a , b , c ], ([0 , 0 , 0 ], [0 , 1 , 2 ])), shape = (1 , prim_pts )
694
754
)
755
+ additive = pybamm .Scalar (0 )
695
756
else :
696
757
raise NotImplementedError
697
758
698
759
elif symbol .side == "right" :
699
- dx = submesh_list [0 ].d_nodes [- 1 ]
700
760
701
761
if self .extrapolation == "linear" :
702
- sub_matrix = (1 / dx ) * csr_matrix (
703
- ([- 1 , 1 ], ([0 , 0 ], [prim_pts - 2 , prim_pts - 1 ])),
704
- shape = (1 , prim_pts ),
705
- )
762
+ if pybamm .has_bc_condition_of_form (
763
+ child , symbol .side , bcs , "Neumann"
764
+ ):
765
+ # just use the value from the bc: f'(x*)
766
+ sub_matrix = csr_matrix ((1 , prim_pts ))
767
+ additive = bcs [child .id ][symbol .side ][0 ]
768
+ else :
769
+ # use formula:
770
+ # f'(x*) = (f_N - f_Nm1) / dxNm1
771
+ sub_matrix = (1 / dxNm1 ) * csr_matrix (
772
+ ([- 1 , 1 ], ([0 , 0 ], [prim_pts - 2 , prim_pts - 1 ])),
773
+ shape = (1 , prim_pts ),
774
+ )
775
+ additive = pybamm .Scalar (0 )
776
+
706
777
elif self .extrapolation == "quadratic" :
707
778
a = (2 * dxN + 2 * dxNm1 + dxNm2 ) / (dxNm1 ** 2 + dxNm1 * dxNm2 )
708
779
b = - (2 * dxN + dxNm1 + dxNm2 ) / (dxNm1 * dxNm2 )
@@ -715,6 +786,7 @@ def boundary_value_or_flux(self, symbol, discretised_child):
715
786
),
716
787
shape = (1 , prim_pts ),
717
788
)
789
+ additive = pybamm .Scalar (0 )
718
790
else :
719
791
raise NotImplementedError
720
792
@@ -730,6 +802,10 @@ def boundary_value_or_flux(self, symbol, discretised_child):
730
802
boundary_value .domain = symbol .domain
731
803
boundary_value .auxiliary_domains = symbol .auxiliary_domains
732
804
805
+ additive .domain = symbol .domain
806
+ additive .auxiliary_domains = symbol .auxiliary_domains
807
+ boundary_value += additive
808
+
733
809
return boundary_value
734
810
735
811
def process_binary_operators (self , bin_op , left , right , disc_left , disc_right ):
0 commit comments