Merge commit 'upstream/4.6.1'
[debian/atlc] / src / update_voltage_array.c
diff --git a/src/update_voltage_array.c b/src/update_voltage_array.c
new file mode 100644 (file)
index 0000000..dc48093
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+The code below for calculating the voltage at a point i,j, given the
+voltages and permittivities at the four adjacent points (i,j+1),
+(i,j-1), (i-1,j), and (i+1,j), although I am not convinced it is 
+100% correct in the case of mulitple dielectrics, the errors are 
+still very small. 
+*/
+
+
+#include "config.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif 
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif 
+
+#include "definitions.h"
+
+
+extern int width, height;
+extern double **Er;
+extern unsigned char  **oddity;
+extern int dielectrics_to_consider_just_now;
+extern double r; 
+extern int coupler;
+
+#include "exit_codes.h"
+
+/* The following function updates the voltage on the matrix V_to given data about the 
+oddity of the location i,j and the voltages in the matrix V_from. It does this for n interations
+between rows jmin and jmax inclusive and between columns imain and imax inclusive */
+
+void update_voltage_array(int nmax, int imin, int imax, int jmin, int jmax, double **V_from, double **V_to)
+{
+  int k, i, j, n;  
+  unsigned char oddity_value;
+  double Va, Vb, Vl, Vr, ERa, ERb, ERl, ERr;
+  double Vnew, g;
+
+  if (dielectrics_to_consider_just_now==1)
+    g=r;
+  else 
+    g=1; 
+  for(n=0; n  < nmax; ++n)
+    for(k=0; k < 4; ++k)
+      for (i = k&1 ? imax : imin;   k&1 ? i >=imin : i <= imax ;  k&1 ? i-- : i++)
+        for (j = (k==0 || k ==3) ? jmin : jmax; (k ==0 || k == 3)  ? j <= jmax : j >= jmin ; (k == 0 || k ==3) ?  j++ : j--){
+          oddity_value=oddity[i][j];
+
+          if( oddity_value == CONDUCTOR_ZERO_V ){  
+            V_to[i][j]=0.0;
+          }
+
+          else if( oddity_value == CONDUCTOR_PLUS_ONE_V ){  
+            V_to[i][j]=1.0;
+          }
+
+          else if( oddity_value == CONDUCTOR_MINUS_ONE_V ){  
+            V_to[i][j]=-1.0;
+          }
+
+          else if( oddity_value == TOP_LEFT_CORNER ) {  /* top left */
+            Vnew=0.5*(V_from[1][0]+V_from[0][1]);               
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+          else if( oddity_value == TOP_RIGHT_CORNER ) {
+            Vnew=0.5*(V_from[width-2][0]+V_from[width-1][1]);         /* top right */
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if(oddity_value == BOTTOM_LEFT_CORNER) {
+            Vnew=0.5*(V_from[0][height-2]+V_from[1][height-1]);       /* bottom left */
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == BOTTOM_RIGHT_CORNER) {   
+            Vnew=0.5*(V_from[width-2][height-1]+V_from[width-1][height-2]); /* bottom right */
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          /* Now the sides */
+
+          else if( oddity_value == ORDINARY_POINT_LEFT_EDGE ){  /* left hand side  */
+            Vnew=0.25*(V_from[0][j-1]+V_from[0][j+1] + 2*V_from[1][j]);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == ORDINARY_POINT_RIGHT_EDGE){   /* right hand side */
+            Vnew=0.25*(V_from[width-1][j+1]+V_from[width-1][j-1]+2*V_from[width-2][j]);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+        
+          else if( oddity_value == ORDINARY_POINT_TOP_EDGE ){ /* top row */ 
+            Vnew=0.25*(V_from[i-1][0]+V_from[i+1][0]+2*V_from[i][1]);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == ORDINARY_POINT_BOTTOM_EDGE ){   /* bottom row */ 
+            Vnew=0.25*(V_from[i-1][height-1]+V_from[i+1][height-1]+2*V_from[i][height-2]);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if ( oddity_value == ORDINARY_INTERIOR_POINT || (oddity_value>=DIFFERENT_DIELECTRIC_ABOVE_AND_RIGHT && oddity_value < UNDEFINED_ODDITY && dielectrics_to_consider_just_now == 1) ) {
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=(Va+Vb+Vl+Vr)/4.0;
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+         }
+
+         /* I'm not sure the following equations, which compute the voltage  
+         where there is a metal around are okay. One line of thought would 
+         say that the same equations as normal  i.e.
+          v_new=(v(i+1,j_+v(i-1,j)+v(i,j-1)+v(i,j+1))/4 should be used
+         but then since the electric field across the metal surface is zero,
+         the equation that was used to derrive  that equation is not valid.
+
+         Another thought of mine is that voltage near a metal will be more affected
+         by the metal than the dielectric, since the nearest part of the metal is at
+         at the same voltage as the node, whereas for a dielectric is less so. Hence
+         the following seems a sensible solution. Since the metal will have twice 
+         the effect of a dielectric, the voltage at i,j should be weighted such
+         that its effect is more strongly affected by the metal. This seems to 
+         produce reasonably accurate results, but whether this is chance or not
+         I don't know. */
+
+          else if( oddity_value == METAL_ABOVE ){  
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Va/3+2*Vb/3+Vl+Vr);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_BELOW ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vb/3+2*Va/3+Vl+Vr);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_LEFT ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vl/3+2*Vr/3+Va+Vb);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_RIGHT ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vr/3+2*Vl/3+Va+Vb);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_ABOVE_AND_RIGHT ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vr/3+4*Va/3 +2*Vl/3 + 2*Vb/3);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_ABOVE_AND_LEFT ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vl/3+4*Va/3+2*Vr/3+2*Vb/3);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_BELOW_AND_LEFT ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vl/3+4*Vb/3+2*Vr/3+2*Va/3);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+          else if( oddity_value == METAL_BELOW_AND_RIGHT ){   
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            Vnew=0.25*(4*Vb/3+4*Vr/3+2*Va/3+2*Vl/3);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+          }
+
+         /* Again, when there is a change of permittivity, my equations may
+         (probably are wrong). My logic is that if there's and RF field,
+         the impedance is inversly proportional to Er. So if the material
+         above a node is of a higher permittivity, then the 
+         voltage will be closer to that of the node above, becuase of this.
+         The same applies for other directions of change in Er. */
+
+
+          else if(dielectrics_to_consider_just_now > 1){
+
+            Va=V_from[i][j-1]; 
+            Vb=V_from[i][j+1];
+            Vl=V_from[i-1][j];
+            Vr=V_from[i+1][j];
+
+            ERa=Er[i][j-1]; 
+            ERb=Er[i][j+1];
+            ERl=Er[i-1][j];
+            ERr=Er[i+1][j];
+
+            Vnew=(Va * ERa + Vb * ERb + Vl * ERl + Vr * ERr)/(ERa + ERb + ERl + ERr);
+            V_to[i][j]=g*Vnew+(1-g)*V_from[i][j];
+
+         }
+         else if ( (dielectrics_to_consider_just_now == 1 && oddity_value == UNDEFINED_ODDITY) || (dielectrics_to_consider_just_now > 1)) {
+            fprintf(stderr,"Internal error in update_voltage_array.c\n");
+            fprintf(stderr,"i=%d j=%d oddity[%d][%d]=%d\n",i,j,i,j,oddity[i][j]);
+            exit(INTERNAL_ERROR);
+          } /* end if if an internal error */
+
+        } /* end of j loop */
+}