1 /*****************************************************************************/
2 /* 8888888 88888888 88888888 */
5 /* 8 88888888 88888888 */
8 /* 888888 888888888 888888888 */
10 /* A Two-Dimensional General Purpose Semiconductor Simulator. */
13 /* Last update: March 29, 2007 */
17 /* NINT, No.69 P.O.Box, Xi'an City, China */
19 /*****************************************************************************/
20 /* the interface data structure with ng-spice */
24 #include "private/kspimpl.h"
25 #include "private/snesimpl.h"
26 #include "src/snes/impls/tr/tr.h"
32 /* ----------------------------------------------------------------------------
33 * error_norm_pn_Mix1: This function compute X and RHS error norms.
35 void DDM_Mix_Solver_L1E:: error_norm_pn_Mix1(PetscScalar
*x
,PetscScalar
*f
)
43 elec_continuty_norm
= 0;
44 hole_continuty_norm
= 0;
47 for(int z
=0;z
<zone_num
;z
++)
49 if(zonedata
[z
]->material_type
==Semiconductor
)
51 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
52 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
54 potential_norm
+= x
[offset
+0]*x
[offset
+0];
55 electron_norm
+= x
[offset
+1]*x
[offset
+1];
56 hole_norm
+= x
[offset
+2]*x
[offset
+2];
57 possion_norm
+= f
[offset
+0]*f
[offset
+0];
58 elec_continuty_norm
+= f
[offset
+1]*f
[offset
+1];
59 hole_continuty_norm
+= f
[offset
+2]*f
[offset
+2];
63 if(zonedata
[z
]->material_type
==Insulator
)
65 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
66 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
68 potential_norm
+= x
[offset
]*x
[offset
];
69 possion_norm
+= f
[offset
]*f
[offset
];
72 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
74 potential_norm
+= x
[offset
]*x
[offset
];
78 if(zonedata
[z
]->material_type
==Conductor
)
80 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
81 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
83 potential_norm
+= x
[offset
]*x
[offset
];
84 possion_norm
+= f
[offset
]*f
[offset
];
90 potential_norm
= sqrt(potential_norm
);
91 electron_norm
= sqrt(electron_norm
);
92 hole_norm
= sqrt(hole_norm
);
94 possion_norm
= sqrt(possion_norm
);
95 elec_continuty_norm
= sqrt(elec_continuty_norm
);
96 hole_continuty_norm
= sqrt(hole_continuty_norm
);
100 /* ----------------------------------------------------------------------------
101 * Convergence Test function for line search method.
103 PetscErrorCode
LineSearch_ConvergenceTest_Mix1(SNES snes
,PetscInt it
,PetscReal xnorm
, PetscReal pnorm
, PetscReal fnorm
,
104 SNESConvergedReason
*reason
,void *dummy
)
106 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)dummy
;
108 *reason
= SNES_CONVERGED_ITERATING
;
111 snes
->ttol
= fnorm
*snes
->rtol
;
112 gss_log
.string_buf()<<" "<<"its\t"<<"| Eq(V) | "<<"| Eq(n) | "<<"| Eq(p) | "<<"|delta x|\n"
113 <<"----------------------------------------------------------------------\n";
117 gss_log
.string_buf().precision(3);
118 gss_log
.string_buf()<<" "<<it
<<"\t"
119 <<ps
->possion_norm
<<" "
120 <<ps
->elec_continuty_norm
<<" "
121 <<ps
->hole_continuty_norm
<<" "
124 gss_log
.string_buf().precision(6);
128 *reason
= SNES_DIVERGED_FNORM_NAN
;
130 else if (ps
->possion_norm
< ps
->possion_abs_toler
&&
131 ps
->elec_continuty_norm
< ps
->elec_continuty_abs_toler
&&
132 ps
->hole_continuty_norm
< ps
->hole_continuty_abs_toler
)
134 *reason
= SNES_CONVERGED_FNORM_ABS
;
136 else if (snes
->nfuncs
>= snes
->max_funcs
)
138 *reason
= SNES_DIVERGED_FUNCTION_COUNT
;
143 if (fnorm
<= snes
->ttol
)
145 *reason
= SNES_CONVERGED_FNORM_RELATIVE
;
147 else if (pnorm
< ps
->relative_toler
&&
148 ps
->possion_norm
< ps
->toler_relax
*ps
->possion_abs_toler
&&
149 ps
->elec_continuty_norm
< ps
->toler_relax
*ps
->elec_continuty_abs_toler
&&
150 ps
->hole_continuty_norm
< ps
->toler_relax
*ps
->hole_continuty_abs_toler
)
152 *reason
= SNES_CONVERGED_PNORM_RELATIVE
;
158 gss_log
.string_buf()<<"----------------------------------------------------------------------\n"
159 <<" "<<SNESConvergedReasons
[*reason
]<<" *residual norm = "<<fnorm
<<"\n\n\n";
168 /* ----------------------------------------------------------------------------
169 * Convergence Test function for trust region method.
171 PetscErrorCode
TrustRegion_ConvergenceTest_Mix1(SNES snes
,PetscInt it
,PetscReal xnorm
, PetscReal pnorm
, PetscReal fnorm
,
172 SNESConvergedReason
*reason
,void *dummy
)
174 SNES_TR
*neP
= (SNES_TR
*)snes
->data
;
175 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)dummy
;
179 gss_log
.string_buf()<<" "<<"its\t"<<"| Eq(V) | "<<"| Eq(n) | "<<"| Eq(p) | "<<"|delta x|\n"
180 <<"----------------------------------------------------------------------\n";
184 gss_log
.string_buf().precision(3);
185 gss_log
.string_buf()<<" "<<ps
->its
++<<"\t"
186 <<ps
->possion_norm
<<" "
187 <<ps
->elec_continuty_norm
<<" "
188 <<ps
->hole_continuty_norm
<<" "
191 gss_log
.string_buf().precision(6);
193 *reason
= SNES_CONVERGED_ITERATING
;
197 snes
->ttol
= fnorm
*snes
->rtol
;
202 *reason
= SNES_DIVERGED_FNORM_NAN
;
204 else if (neP
->delta
< xnorm
* snes
->deltatol
)
206 if( ps
->possion_norm
< ps
->toler_relax
*ps
->possion_abs_toler
&&
207 ps
->elec_continuty_norm
< ps
->toler_relax
*ps
->elec_continuty_abs_toler
&&
208 ps
->hole_continuty_norm
< ps
->toler_relax
*ps
->hole_continuty_abs_toler
)
210 *reason
= SNES_CONVERGED_TR_DELTA
;
214 *reason
= SNES_DIVERGED_LOCAL_MIN
;
217 else if (ps
->possion_norm
< ps
->possion_abs_toler
&&
218 ps
->elec_continuty_norm
< ps
->elec_continuty_abs_toler
&&
219 ps
->hole_continuty_norm
< ps
->hole_continuty_abs_toler
)
221 *reason
= SNES_CONVERGED_FNORM_ABS
;
223 else if (snes
->nfuncs
>= snes
->max_funcs
)
225 *reason
= SNES_DIVERGED_FUNCTION_COUNT
;
230 if (fnorm
<= snes
->ttol
)
232 *reason
= SNES_CONVERGED_FNORM_RELATIVE
;
234 else if (pnorm
< ps
->relative_toler
&&
235 ps
->possion_norm
< ps
->toler_relax
*ps
->possion_abs_toler
&&
236 ps
->elec_continuty_norm
< ps
->toler_relax
*ps
->elec_continuty_abs_toler
&&
237 ps
->hole_continuty_norm
< ps
->toler_relax
*ps
->hole_continuty_abs_toler
)
239 *reason
= SNES_CONVERGED_PNORM_RELATIVE
;
243 if (snes
->nfuncs
>= snes
->max_funcs
)
245 *reason
= SNES_DIVERGED_FUNCTION_COUNT
;
249 gss_log
.string_buf()<<"----------------------------------------------------------------------\n"
250 <<" "<<SNESConvergedReasons
[*reason
]<<" *residual norm = "<<fnorm
<<"\n\n\n";
259 /* ----------------------------------------------------------------------------
260 * form_function_pn: This function setup DDM equation F(x)=0
262 void DDM_Mix_Solver_L1E::form_function_pn_Mix1(PetscScalar
*x
,PetscScalar
*f
)
264 // compute flux along triangle edges. semiconductor zone only
265 for(int z
=0;z
<zone_num
;z
++)
266 if(zonedata
[z
]->material_type
==Semiconductor
)
268 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
269 for(int i
=0;i
<zone
[z
].datri
.size();i
++)
271 Tri
*ptri
= &zone
[z
].datri
[i
];
272 pzonedata
->F1E_Tri_ddm(ptri
,x
,f
,zofs
);
276 for(int z
=0;z
<zone_num
;z
++)
279 if(zonedata
[z
]->material_type
==Semiconductor
)
281 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
282 // compute electrode current.
283 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
285 if(bc
[pzonedata
->electrode
[i
]].BCType
==OhmicContact
)
286 pzonedata
->F1E_mix_om_electrode_current(i
,x
,f
,ODE_formula
,zofs
,bc
,DeviceDepth
);
287 if(bc
[pzonedata
->electrode
[i
]].BCType
==SchottkyContact
)
288 pzonedata
->F1E_mix_stk_electrode_current(i
,x
,f
,ODE_formula
,zofs
,bc
,DeviceDepth
);
289 if(bc
[pzonedata
->electrode
[i
]].BCType
==InsulatorContact
)
290 pzonedata
->F1E_mix_ins_electrode_current(i
,x
,f
,ODE_formula
,zofs
,bc
,DeviceDepth
);
292 // process cell variables and boundaries.
293 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
295 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
296 if(!pcell
->bc_index
||bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
297 pzonedata
->F1E_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
298 //process the electrode bc for mix simulation.
299 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==OhmicContact
)
300 pzonedata
->F1E_mix_ddm_ombc(i
,x
,f
,ODE_formula
,zofs
,bc
);
301 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==SchottkyContact
)
302 pzonedata
->F1E_mix_ddm_stkbc(i
,x
,f
,ODE_formula
,zofs
,bc
);
303 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorContact
)
304 pzonedata
->F1E_mix_ddm_insulator_gate(i
,x
,f
,ODE_formula
,zofs
,bc
);
305 // the routine for interface BC do not change, share the DDML1E routine.
306 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorInterface
)
308 InsulatorInterfaceBC
*pbc
;
309 pbc
= dynamic_cast<InsulatorInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
310 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
311 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
312 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
313 pzonedata
->F1E_ddm_interface(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
315 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==HomoInterface
)
317 HomoInterfaceBC
*pbc
;
318 pbc
= dynamic_cast<HomoInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
319 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
320 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
321 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
322 pzonedata
->F1E_ddm_homojunction(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
324 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==HeteroInterface
)
326 HeteroInterfaceBC
*pbc
;
327 pbc
= dynamic_cast<HeteroInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
328 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
329 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
330 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
331 pzonedata
->F1E_ddm_heterojunction(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
333 else //prevent some mistakes caused by inexact bc
334 pzonedata
->F1E_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
339 if(zonedata
[z
]->material_type
==Insulator
)
341 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
342 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
344 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
345 if(!pcell
->bc_index
||bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
346 pzonedata
->F1_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
347 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==GateContact
)
348 pzonedata
->F1_mix_ddm_gatebc(i
,x
,f
,ODE_formula
,zofs
,bc
);
349 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==ChargedContact
)
350 pzonedata
->F1_ddm_chargebc(i
,x
,f
,ODE_formula
,zofs
,bc
);
351 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Electrode_Insulator
)
353 ElectrodeInsulatorBC
*pbc
;
354 pbc
= dynamic_cast<ElectrodeInsulatorBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
355 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
356 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
357 ElZone
* pz
= dynamic_cast<ElZone
*>(zonedata
[n_zone
]);
358 pzonedata
->F1_ddm_electrode_insulator_interface(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
360 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorInterface
)
362 InsulatorInterfaceBC
*pbc
;
363 pbc
= dynamic_cast<InsulatorInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
364 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
365 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
366 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
367 pzonedata
->F1_ddm_semiconductor_insulator_interface(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
369 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Insulator_Insulator
)
371 InsulatorInsulatorBC
*pbc
;
372 pbc
= dynamic_cast<InsulatorInsulatorBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
373 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
374 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
375 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
376 pzonedata
->F1_ddm_insulator_insulator_interface(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
378 else //prevent some mistakes caused by inexact bc
379 pzonedata
->F1_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
381 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
383 //compute gate electrode current
384 if(bc
[pzonedata
->electrode
[i
]].BCType
==GateContact
)
385 pzonedata
->F1_mix_gate_electrode_current(i
,x
,f
,ODE_formula
,zofs
,bc
,DeviceDepth
);
386 //addtional equ for charge electrode
387 if(bc
[pzonedata
->electrode
[i
]].BCType
==ChargedContact
)
388 pzonedata
->F1_charge_electrode(i
,x
,f
,ODE_formula
,zofs
,bc
);
393 if(zonedata
[z
]->material_type
==Conductor
)
395 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
396 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
398 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
399 if(!pcell
->bc_index
|| bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
400 pzonedata
->F1_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
401 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Electrode_Insulator
)
402 pzonedata
->F1_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
403 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==OhmicContact
)
405 OhmicBC
*pbc
= dynamic_cast<OhmicBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
406 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
407 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
408 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
409 pzonedata
->F1_ddm_om_contact(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
411 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==SchottkyContact
)
413 SchottkyBC
*pbc
= dynamic_cast<SchottkyBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
414 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
415 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
416 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
417 pzonedata
->F1_ddm_om_contact(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
419 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==GateContact
)
421 GateBC
*pbc
= dynamic_cast<GateBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
422 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
423 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
424 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
425 pzonedata
->F1_ddm_gate_contact(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
427 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==ChargedContact
)
429 ChargedContactBC
*pbc
= dynamic_cast<ChargedContactBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
430 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
431 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
432 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
433 pzonedata
->F1_ddm_charge_contact(i
,x
,f
,ODE_formula
,zofs
,bc
,pz
,n_node
);
435 else //prevent some mistakes caused by inexact bc
436 pzonedata
->F1_ddm_inner(i
,x
,f
,ODE_formula
,zofs
);
444 /* ----------------------------------------------------------------------------
445 * form_jacobian_pn: This function setup jacobian matrix F'(x) of DDM equation F(x)=0
446 * dual carrier edition
448 void DDM_Mix_Solver_L1E::form_jacobian_pn_Mix1(PetscScalar
*x
, Mat
*jac
, Mat
*jtmp
)
451 //Compute Jacobian entries for flux along triangle edges.
452 for(int z
=0;z
<zone_num
;z
++)
454 if(zonedata
[z
]->material_type
==Semiconductor
)
456 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
458 // compute flux Jacobian along triangle edges
459 for(int i
=0;i
<zone
[z
].datri
.size();i
++)
461 Tri
*ptri
= &zone
[z
].datri
[i
];
462 pzonedata
->J1E_Tri_ddm(ptri
,x
,jtmp
,zofs
);
467 MatAssemblyBegin(*jtmp
,MAT_FINAL_ASSEMBLY
);
468 MatAssemblyEnd(*jtmp
,MAT_FINAL_ASSEMBLY
);
470 //Compute Jacobian entries and insert into matrix.
471 for(int z
=0;z
<zone_num
;z
++)
473 if(zonedata
[z
]->material_type
==Semiconductor
)
475 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
477 // process cell variables and boundaries.
478 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
480 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
481 if(!pcell
->bc_index
||bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
482 pzonedata
->J1E_ddm_inner(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
);
483 //process the electrode bc for mix simulation.
484 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==OhmicContact
)
485 pzonedata
->J1E_mix_ddm_ombc(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
,bc
);
486 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==SchottkyContact
)
487 pzonedata
->J1E_mix_ddm_stkbc(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
,bc
);
488 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorContact
)
489 pzonedata
->J1E_mix_ddm_insulator_gate(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
,bc
);
490 // the routine for interface BC do not change, share the DDML1E routine.
491 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorInterface
)
493 InsulatorInterfaceBC
*pbc
;
494 pbc
= dynamic_cast<InsulatorInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
495 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
496 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
497 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
498 pzonedata
->J1E_ddm_interface(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
,bc
,pz
,n_node
);
500 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==HomoInterface
)
502 HomoInterfaceBC
*pbc
;
503 pbc
= dynamic_cast<HomoInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
504 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
505 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
506 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
507 pzonedata
->J1E_ddm_homojunction(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
,bc
,pz
,n_node
);
509 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==HeteroInterface
)
511 HeteroInterfaceBC
*pbc
;
512 pbc
= dynamic_cast<HeteroInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
513 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
514 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
515 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
516 pzonedata
->J1E_ddm_heterojunction(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
,bc
,pz
,n_node
);
518 else //prevent some mistakes caused by inexact bc
519 pzonedata
->J1E_ddm_inner(i
,x
,jac
,&JTmp
,ODE_formula
,zofs
);
524 if(zonedata
[z
]->material_type
==Insulator
)
526 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
528 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
531 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
532 if(!pcell
->bc_index
||bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
533 pzonedata
->J1_ddm_inner(i
,x
,jac
,ODE_formula
,zofs
);
534 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==GateContact
)
535 pzonedata
->J1_mix_ddm_gatebc(i
,x
,jac
,ODE_formula
,zofs
,bc
);
536 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==ChargedContact
)
537 pzonedata
->J1_ddm_chargebc(i
,x
,jac
,ODE_formula
,zofs
,bc
);
538 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==IF_Electrode_Insulator
)
540 ElectrodeInsulatorBC
*pbc
;
541 pbc
= dynamic_cast<ElectrodeInsulatorBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
542 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
543 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
544 ElZone
* pz
= dynamic_cast<ElZone
*>(zonedata
[n_zone
]);
545 pzonedata
->J1_ddm_electrode_insulator_interface(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
547 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorInterface
)
549 InsulatorInterfaceBC
*pbc
;
550 pbc
= dynamic_cast<InsulatorInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
551 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
552 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
553 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
554 pzonedata
->J1_ddm_semiconductor_insulator_interface(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
556 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Insulator_Insulator
)
558 InsulatorInsulatorBC
*pbc
;
559 pbc
= dynamic_cast<InsulatorInsulatorBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
560 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
561 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
562 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
563 pzonedata
->J1_ddm_insulator_insulator_interface(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
565 else //prevent some mistakes caused by inexact bc
566 pzonedata
->J1_ddm_inner(i
,x
,jac
,ODE_formula
,zofs
);
568 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
570 //addtional equ for charge electrode
571 if(bc
[pzonedata
->electrode
[i
]].BCType
==ChargedContact
)
572 pzonedata
->J1_charge_electrode(i
,x
,jac
,ODE_formula
,zofs
,bc
);
577 if(zonedata
[z
]->material_type
==Conductor
)
579 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
580 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
582 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
583 if(!pcell
->bc_index
|| bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
584 pzonedata
->J1_ddm_inner(i
,x
,jac
,ODE_formula
,zofs
);
585 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Electrode_Insulator
)
586 pzonedata
->J1_ddm_inner(i
,x
,jac
,ODE_formula
,zofs
);
587 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==OhmicContact
)
589 OhmicBC
*pbc
= dynamic_cast<OhmicBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
590 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
591 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
592 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
593 pzonedata
->J1_ddm_om_contact(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
595 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==SchottkyContact
)
597 SchottkyBC
*pbc
= dynamic_cast<SchottkyBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
598 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
599 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
600 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
601 pzonedata
->J1_ddm_stk_contact(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
603 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==GateContact
)
605 GateBC
*pbc
= dynamic_cast<GateBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
606 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
607 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
608 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
609 pzonedata
->J1_ddm_gate_contact(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
611 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==ChargedContact
)
613 ChargedContactBC
*pbc
= dynamic_cast<ChargedContactBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
614 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
615 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
616 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
617 pzonedata
->J1_ddm_charge_contact(i
,x
,jac
,ODE_formula
,zofs
,bc
,pz
,n_node
);
619 else //prevent some mistakes caused by inexact bc
620 pzonedata
->J1_ddm_inner(i
,x
,jac
,ODE_formula
,zofs
);
628 /* ----------------------------------------------------------------------------
629 * SNES_form_function_pn_Mix1: wrap function for petsc nonlinear solver
631 PetscErrorCode
SNES_form_function_pn_Mix1(SNES snes
, Vec x
,Vec f
,void *dummy
)
634 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)dummy
;
636 //Get pointers to vector data.
640 ps
->form_function_pn_Mix1(xx
,ff
);
641 ps
->error_norm_pn_Mix1(xx
,ff
);
644 VecRestoreArray(x
,&xx
);
645 VecRestoreArray(f
,&ff
);
646 VecNorm(f
,NORM_2
,&ps
->norm
);
651 /* ----------------------------------------------------------------------------
652 * SNES_form_jacobian_pn_Mix1: wrap function for petsc nonlinear solver
654 PetscErrorCode
SNES_form_jacobian_pn_Mix1(SNES snes
, Vec x
,Mat
*jac
,Mat
*B
,MatStructure
*flag
,void *dummy
)
657 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)dummy
;
658 //Get pointer to vector data
661 MatZeroEntries(*jac
);
662 MatZeroEntries(ps
->JTmp
);
664 ps
->form_jacobian_pn_Mix1(xx
,jac
,&ps
->JTmp
);
665 *flag
= SAME_NONZERO_PATTERN
;
667 VecRestoreArray(x
,&xx
);
669 MatAssemblyBegin(*jac
,MAT_FINAL_ASSEMBLY
);
670 MatAssemblyEnd(*jac
,MAT_FINAL_ASSEMBLY
);
671 //MatView(*jac,PETSC_VIEWER_DRAW_WORLD);
675 PetscErrorCode
LimitorByBankRose_Mix1(SNES snes
, Vec x
,Vec y
,Vec w
,void *checkctx
, PetscTruth
*changed_y
,PetscTruth
*changed_w
)
678 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)checkctx
;
686 SNESGetIterationNumber(snes
,&it
);
687 static PetscScalar K
;
692 VecDuplicate(x
,&gk0
);
693 VecDuplicate(x
,&gk1
);
694 SNESComputeFunction(snes
,x
,gk0
);
695 PetscScalar gk0_norm
;
696 VecNorm(gk0
,NORM_2
,&gk0_norm
);
699 PetscScalar tk
=1.0/(1+K
*gk0_norm
);
704 SNESComputeFunction(snes
,w
,gk1
);
705 PetscScalar gk1_norm
;
706 VecNorm(gk1
,NORM_2
,&gk1_norm
);
707 if((1-gk1_norm
/gk0_norm
)<0.9*tk
)
719 //prevent negative carrier density
721 for(int z
=0;z
<ps
->zone_num
;z
++)
723 if(ps
->zonedata
[z
]->material_type
==Semiconductor
)
725 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(ps
->zonedata
[z
]);
726 for(int i
=0;i
<pzonedata
->pzone
->davcell
.size();i
++)
728 if(fabs(yy
[offset
])>1.0) {ww
[offset
] = xx
[offset
] - dsign(yy
[offset
])*1.0;flag
=1;}
729 if (ww
[offset
+1] <0 ) {ww
[offset
+1]=1.0*pow(ps
->scale_unit
.s_centimeter
,-3);flag
=1;}
730 if (ww
[offset
+2] <0 ) {ww
[offset
+2]=1.0*pow(ps
->scale_unit
.s_centimeter
,-3);flag
=1;}
734 else if(ps
->zonedata
[z
]->material_type
==Insulator
)
736 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(ps
->zonedata
[z
]);
737 offset
+= pzonedata
->pzone
->davcell
.size();
738 offset
+= pzonedata
->electrode
.size();
740 else if(ps
->zonedata
[z
]->material_type
==Conductor
)
742 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(ps
->zonedata
[z
]);
743 offset
+= pzonedata
->pzone
->davcell
.size();
749 *changed_y
= PETSC_FALSE
;
750 *changed_w
= PETSC_TRUE
;
754 VecRestoreArray(x
,&xx
);
755 VecRestoreArray(y
,&yy
);
756 VecRestoreArray(w
,&ww
);
761 PetscErrorCode
LimitorByPotential_Mix1(SNES snes
, Vec x
,Vec y
,Vec w
,void *checkctx
, PetscTruth
*changed_y
,PetscTruth
*changed_w
)
769 PetscScalar dV_max
=0;
772 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)checkctx
;
774 for(int z
=0;z
<ps
->zone_num
;z
++)
776 if(ps
->zonedata
[z
]->material_type
==Semiconductor
)
778 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(ps
->zonedata
[z
]);
779 for(int i
=0;i
<pzonedata
->pzone
->davcell
.size();i
++)
781 if(fabs(yy
[offset
])>dV_max
) {dV_max
=fabs(yy
[offset
]); }
785 else if(ps
->zonedata
[z
]->material_type
==Insulator
)
787 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(ps
->zonedata
[z
]);
788 offset
+= pzonedata
->pzone
->davcell
.size();
789 offset
+= pzonedata
->electrode
.size();
791 else if(ps
->zonedata
[z
]->material_type
==Conductor
)
793 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(ps
->zonedata
[z
]);
794 offset
+= pzonedata
->pzone
->davcell
.size();
797 if(dV_max
<1e-2) return(0);
799 //do logarithmic potential damping;
800 PetscScalar Vt
=0.026*ps
->LatticeTemp
;
801 PetscScalar f
= log(1+dV_max
/Vt
)/(dV_max
/Vt
);
803 //prevent negative carrier density
805 for(int z
=0;z
<ps
->zone_num
;z
++)
807 if(ps
->zonedata
[z
]->material_type
==Semiconductor
)
809 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(ps
->zonedata
[z
]);
810 for(int i
=0;i
<pzonedata
->pzone
->davcell
.size();i
++)
812 ww
[offset
] = xx
[offset
] - f
*yy
[offset
];
813 if (ww
[offset
+1] <0 ) ww
[offset
+1]=1.0*pow(ps
->scale_unit
.s_centimeter
,-3);
814 if (ww
[offset
+2] <0 ) ww
[offset
+2]=1.0*pow(ps
->scale_unit
.s_centimeter
,-3);
818 else if(ps
->zonedata
[z
]->material_type
==Insulator
)
820 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(ps
->zonedata
[z
]);
821 for(int i
=0;i
<pzonedata
->pzone
->davcell
.size();i
++)
823 ww
[offset
] = xx
[offset
] - f
*yy
[offset
];
826 offset
+= pzonedata
->electrode
.size();
828 else if(ps
->zonedata
[z
]->material_type
==Conductor
)
830 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(ps
->zonedata
[z
]);
831 for(int i
=0;i
<pzonedata
->pzone
->davcell
.size();i
++)
833 ww
[offset
] = xx
[offset
] - f
*yy
[offset
];
839 VecRestoreArray(x
,&xx
);
840 VecRestoreArray(y
,&yy
);
841 VecRestoreArray(w
,&ww
);
843 *changed_y
= PETSC_FALSE
;
844 *changed_w
= PETSC_TRUE
;
849 PetscErrorCode
LimitorNonNegativeCarrier_Mix1(SNES snes
, Vec x
,Vec y
,Vec w
,void *checkctx
, PetscTruth
*changed_y
,PetscTruth
*changed_w
)
858 DDM_Mix_Solver_L1E
*ps
= (DDM_Mix_Solver_L1E
*)checkctx
;
861 for(int z
=0;z
<ps
->zone_num
;z
++)
863 if(ps
->zonedata
[z
]->material_type
==Semiconductor
)
865 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(ps
->zonedata
[z
]);
866 for(int i
=0;i
<pzonedata
->pzone
->davcell
.size();i
++)
868 if(fabs(yy
[offset
])>1.0) {ww
[offset
] = xx
[offset
] - dsign(yy
[offset
])*1.0;flag
=1;}
869 if (ww
[offset
+1] <0 ) {ww
[offset
+1]=1.0*pow(ps
->scale_unit
.s_centimeter
,-3);flag
=1;}
870 if (ww
[offset
+2] <0 ) {ww
[offset
+2]=1.0*pow(ps
->scale_unit
.s_centimeter
,-3);flag
=1;}
874 else if(ps
->zonedata
[z
]->material_type
==Insulator
)
876 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(ps
->zonedata
[z
]);
877 offset
+= pzonedata
->pzone
->davcell
.size();
878 offset
+= pzonedata
->electrode
.size();
880 else if(ps
->zonedata
[z
]->material_type
==Conductor
)
882 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(ps
->zonedata
[z
]);
883 offset
+= pzonedata
->pzone
->davcell
.size();
886 VecRestoreArray(x
,&xx
);
887 VecRestoreArray(y
,&yy
);
888 VecRestoreArray(w
,&ww
);
892 *changed_y
= PETSC_FALSE
;
893 *changed_w
= PETSC_TRUE
;
900 /* ----------------------------------------------------------------------------
901 * DDM_Mix_Solver_L1E::init_solver: This function do initial setup for nonlinear solver
903 int DDM_Mix_Solver_L1E::init_solver(SolveDefine
&sv
)
905 gss_log
.string_buf()<<"DDM Level 1E Device/Circuit Mix Solver init...\n";
909 if(NDEVServer(sv
.port
,listener
,client
))
911 gss_log
.string_buf()<<"I can't connect to ngspice, mix simulation stopped.\n";
915 //get ngspice terminal information
916 recv(client
,&(Deviceinfo
),sizeof(sDeviceinfo
),MSG_FLAG
);
917 gss_log
.string_buf()<<"Ngspice demands device "<<Deviceinfo
.NDEVname
<<" to be calculated.\n";
919 for(int i
=0;i
<Deviceinfo
.term
;i
++)
921 recv(client
,&(PINinfos
[i
]),sizeof(sPINinfo
),MSG_FLAG
);
922 if(!bc
.Get_electrode_pointer_nocase(PINinfos
[i
].name
))
924 gss_log
.string_buf()<<"I can't link terminal name "<<PINinfos
[i
].name
<<" to GSS eletrode boundary.\n";
928 gss_log
.string_buf()<<" Terminal "<<i
<<": "<<PINinfos
[i
].name
<<"\n";
933 relative_toler
= sv
.relative_toler
;
934 toler_relax
= sv
.toler_relax
;
935 possion_abs_toler
= sv
.possion_abs_toler
;
936 elec_continuty_abs_toler
= sv
.elec_continuty_abs_toler
;
937 hole_continuty_abs_toler
= sv
.hole_continuty_abs_toler
;
939 // compute the scale of problem.
940 zofs
.resize(zone_num
+1);
942 for(int i
=0;i
<zone_num
;i
++)
944 if(zonedata
[i
]->material_type
==Semiconductor
) //semiconductor zone
946 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
947 N
+= 3*pzonedata
->pzone
->davcell
.size();
948 //NO extra electrode equation needs.
951 else if(zonedata
[i
]->material_type
==Insulator
) //Insulator zone
953 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[i
]);
954 N
+= zone
[i
].davcell
.size();
955 N
+= pzonedata
->electrode
.size(); //additional equation for charged electrode
958 else if(zonedata
[i
]->material_type
==Conductor
) //Electrode zone
960 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[i
]);
961 N
+= zone
[i
].davcell
.size();
964 else //other zones, such as PML and vacuum
970 VecCreateSeq(PETSC_COMM_SELF
,N
,&x
);
972 for(int i
=0;i
<Deviceinfo
.term
;i
++)
974 VecDuplicate(x
,&PINconds
[i
].pdI_pdw
);
975 VecDuplicate(x
,&PINconds
[i
].pdF_pdV
);
976 VecDuplicate(x
,&PINconds
[i
].pdw_pdV
);
979 //Evaluate initial guess,importnat for newton solver
980 PetscScalar init_value
[3];
983 for(int z
=0;z
<zone_num
;z
++)
985 if(zonedata
[z
]->material_type
==Semiconductor
)
987 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
988 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
993 init_value
[0] = pzonedata
->fs
[i
].P
;
994 init_value
[1] = pzonedata
->fs
[i
].n
;
995 init_value
[2] = pzonedata
->fs
[i
].p
;
996 VecSetValues(x
,3,index
,init_value
,INSERT_VALUES
);
1001 if(zonedata
[z
]->material_type
==Insulator
)
1003 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
1004 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1006 VecSetValue(x
,offset
,pzonedata
->fs
[i
].P
,INSERT_VALUES
);
1009 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
1011 VecSetValue(x
,offset
,0,INSERT_VALUES
);
1016 if(zonedata
[z
]->material_type
==Conductor
)
1018 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
1019 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1021 VecSetValue(x
,offset
,pzonedata
->fs
[i
].P
,INSERT_VALUES
);
1028 VecAssemblyBegin(x
);
1031 // Create Jacobian matrix data structure
1032 // pre-alloc approximate memory
1033 int *nnz
= new int[N
];
1035 for(int i
=0;i
<zone_num
;i
++)
1037 //semiconductor zone
1038 if(zonedata
[i
]->material_type
==Semiconductor
)
1040 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
1041 for(int j
=0;j
<pzonedata
->pzone
->davcell
.size();j
++)
1043 const VoronoiCell
* pcell
= pzonedata
->pzone
->davcell
.GetPointer(j
);
1044 //inner node, alloc exact memory.
1045 if(!pcell
->bc_index
|| bc
[pcell
->bc_index
-1].psegment
->interface
==-1)
1047 *p
++ = 3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
1048 *p
++ = 3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
1049 *p
++ = 3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
1051 else //interface node, slightly more than needed.
1053 *p
++ = 3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
1054 *p
++ = 3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
1055 *p
++ = 3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
1059 //Insulator zones, poisson equation only
1060 if(zonedata
[i
]->material_type
==Insulator
)
1062 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[i
]);
1063 for(int j
=0;j
<zone
[i
].davcell
.size();j
++)
1064 *p
++ = 1*(zone
[i
].davcell
[j
].nb_num
+1);
1065 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
1066 *p
++ = bc
[pzonedata
->electrode
[j
]].psegment
->node_array
.size()+1;
1068 //Electrode zones, poisson equation only
1069 if(zonedata
[i
]->material_type
==Conductor
)
1071 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[i
]);
1072 for(int j
=0;j
<zone
[i
].davcell
.size();j
++)
1073 *p
++ = 1*(zone
[i
].davcell
[j
].nb_num
+1);
1077 MatCreate(PETSC_COMM_SELF
,&J
);
1078 MatSetSizes(J
,N
,N
,N
,N
);
1079 if(sv
.LS
=="superlu")
1081 #ifdef PETSC_HAVE_SUPERLU
1082 MatSetType(J
,MATSUPERLU
);
1084 MatSetType(J
,MATSEQAIJ
);
1087 else if(sv
.LS
=="umfpack")
1089 #ifdef PETSC_HAVE_UMFPACK
1090 MatSetType(J
,MATUMFPACK
);
1092 MatSetType(J
,MATSEQAIJ
);
1097 MatSetType(J
,MATSEQAIJ
);
1099 MatSeqAIJSetPreallocation(J
,0,nnz
);
1101 MatCreateSeqAIJ(PETSC_COMM_SELF
,N
,N
,0,nnz
,&JTmp
);
1104 SNESCreate(PETSC_COMM_WORLD
,&snes
);
1105 SNESSetFunction(snes
,r
,SNES_form_function_pn_Mix1
,this);
1106 SNESSetJacobian(snes
,J
,J
,SNES_form_jacobian_pn_Mix1
,this);
1108 // set the newton method
1109 SNESSetType(snes
,SNESLS
); //default method
1111 // the maximum number of iterations
1112 PetscInt maxit
= sv
.maxit
;
1114 SNESSetType(snes
,SNESLS
); //default method
1115 if(sv
.NS
==LineSearch
|| sv
.NS
==Basic
)
1117 if(sv
.NS
==LineSearch
)
1118 SNESLineSearchSet(snes
,SNESLineSearchCubic
,PETSC_NULL
);
1120 SNESLineSearchSet(snes
,SNESLineSearchNo
,PETSC_NULL
);
1122 if(sv
.Damping
==DampingBankRose
)
1123 SNESLineSearchSetPostCheck(snes
,LimitorByBankRose_Mix1
,this);
1124 else if(sv
.Damping
==DampingPotential
)
1125 SNESLineSearchSetPostCheck(snes
,LimitorByPotential_Mix1
,this);
1127 SNESLineSearchSetPostCheck(snes
,LimitorNonNegativeCarrier_Mix1
,this);
1129 SNESSetTolerances(snes
,1e-12*N
,1e-14,1e-9,maxit
,1000);
1130 SNESSetConvergenceTest(snes
,LineSearch_ConvergenceTest_Mix1
,this);
1132 else if(sv
.NS
==TrustRegion
)
1134 SNESSetType(snes
,SNESTR
);
1135 SNESSetTolerances(snes
,1e-12*N
,1e-14,1e-9,maxit
,1000);
1136 SNESSetTrustRegionTolerance(snes
,1e-30);
1137 SNESSetConvergenceTest(snes
,TrustRegion_ConvergenceTest_Mix1
,this);
1138 //must set TR delta0 to a sufficient large value, or TR can't find real solution.
1139 SNES_TR
*neP
= (SNES_TR
*)snes
->data
;
1142 SNESGetKSP(snes
,&ksp
);
1145 if(sv
.LS
=="lu"||sv
.LS
=="superlu"||sv
.LS
=="umfpack")
1147 KSPSetType(ksp
,KSPPREONLY
);
1149 PCFactorSetReuseOrdering(pc
,PETSC_TRUE
);
1150 PCFactorSetReuseFill(pc
,PETSC_TRUE
);
1151 PCFactorSetPivoting(pc
,1.0);
1152 PCFactorReorderForNonzeroDiagonal(pc
,1e-14);
1153 PCFactorSetShiftNonzero(pc
,1e-12);
1157 KSPSetType(ksp
,sv
.LS
.c_str());
1158 if(sv
.LS
=="gmres") KSPGMRESSetRestart(ksp
,150);
1159 KSPSetTolerances(ksp
,1e-14*N
,1e-25*N
,PETSC_DEFAULT
,max(35,N
/10));
1160 PCSetType(pc
,PCILU
);
1161 PCFactorSetLevels(pc
,3);
1162 PCFactorSetShiftNonzero(pc
,1e-14);
1163 PCFactorReorderForNonzeroDiagonal(pc
,1e-12);
1166 KSPSetFromOptions(ksp
);
1167 SNESSetFromOptions(snes
);
1168 gss_log
.string_buf()<<"DDM Level 1E Device/Circuit Mix Solver init ok.\n";
1174 /* ----------------------------------------------------------------------------
1175 * DDM_Mix_Solver_L1E::do_solve: This function receive ngspice device information.
1177 int DDM_Mix_Solver_L1E::do_solve(SolveDefine
&sv
)
1179 ODE_formula
.clock
= -1e100
;
1183 if (sigsetjmp(net_buf
, 1) == 1) break;
1184 //receive solver information
1185 bytes
=recv(client
,&(CKTInfo
),sizeof(sCKTinfo
),MSG_FLAG
);
1186 //if ngspice terminated, stop loop.
1187 if(bytes
<sizeof(sCKTinfo
))
1189 gss_log
.string_buf()<<"Lost connection to remote ngspice.\n";
1193 switch(CKTInfo
.DEV_CALL
)
1195 case NDEV_LOAD
: DEV_LOAD(); break;
1196 case NDEV_ACCEPT
: DEV_ACCEPT(); break;
1197 case NDEV_CONVERGINCE_TEST
: DEV_CONV_TEST(); break;
1205 int DDM_Mix_Solver_L1E::DEV_LOAD()
1208 //receive terminal voltage of device
1209 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1211 recv(client
,&PINinfos
[i
],sizeof(sPINinfo
),MSG_FLAG
);
1212 bc
.Set_Vapp_nocase(PINinfos
[i
].name
,PINinfos
[i
].V
);
1215 //transient calculation settings
1216 if(CKTInfo
.CKTmode
& MODETRAN
)
1218 ODE_formula
.TimeDependent
= true;
1219 ODE_formula
.BDF_Type
= BDF2
;
1220 if(CKTInfo
.CKTmode
& MODEINITTRAN
) //the first step of transient simulation
1222 gss_log
.string_buf()<<"----------------------------------------------------------------------\n";
1223 gss_log
.string_buf()<<"NGSPICE Transient Mode Start Time = "<<CKTInfo
.time
<<"s dt = "<<CKTInfo
.dt
<<"s\n";
1224 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1226 gss_log
.string_buf()<<"Set V("<<PINinfos
[i
].name
<<") = "<<PINinfos
[i
].V
<<"V\n";
1229 gss_log
.string_buf()<<"----------------------------------------------------------------------\n\n";
1231 ODE_formula
.BDF2_restart
= true;
1233 else if(CKTInfo
.CKTmode
& MODEINITPRED
) //the time matching flag
1235 gss_log
.string_buf()<<"----------------------------------------------------------------------\n";
1236 gss_log
.string_buf()<<"NGSPICE Transient Mode Update Time = "<<CKTInfo
.time
<<"s dt = "<<CKTInfo
.dt
<<"s\n";
1237 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1239 gss_log
.string_buf()<<"Set V("<<PINinfos
[i
].name
<<") = "<<PINinfos
[i
].V
<<"V\n";
1242 if(ODE_formula
.clock
> CKTInfo
.time
*scale_unit
.s_second
)
1244 time_back_recovery();
1245 ODE_formula
.BDF2_restart
= true;
1246 gss_log
.string_buf()<<"NGSPICE back trace...\n";
1251 ODE_formula
.BDF2_restart
= false;
1253 gss_log
.string_buf()<<"----------------------------------------------------------------------\n\n";
1256 ODE_formula
.clock
= CKTInfo
.time
*scale_unit
.s_second
;
1257 // call the real computation routine
1260 //DC calculation settings
1261 else if(CKTInfo
.CKTmode
& MODEDC
)
1263 gss_log
.string_buf()<<"----------------------------------------------------------------------\n";
1264 gss_log
.string_buf()<<"NGSPICE DC Mode\n";
1265 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1267 gss_log
.string_buf()<<"Set V("<<PINinfos
[i
].name
<<") = "<<PINinfos
[i
].V
<<"V\n";
1270 gss_log
.string_buf()<<"----------------------------------------------------------------------\n\n";
1272 ODE_formula
.TimeDependent
= false;
1273 ODE_formula
.dt
= 1e100
;
1274 // call the real computation routine
1278 //get pdI/pdw, pdI/pdV and pdF/pdV for each electrode
1280 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1281 for(int z
=0;z
<zone_num
;z
++)
1283 if(zonedata
[z
]->material_type
==Semiconductor
)
1285 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
1286 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
1287 if(bc
.is_electrode_label_nocase(pzonedata
->electrode
[j
], PINinfos
[i
].name
))
1289 if(bc
[pzonedata
->electrode
[j
]].BCType
==OhmicContact
)
1290 pzonedata
->F1E_mix_om_electrode_Load(pzonedata
->electrode
[j
],PINinfos
[i
].I
,PINconds
[i
].pdI_pdV
,
1291 PINconds
[i
].pdI_pdw
,PINconds
[i
].pdF_pdV
,
1292 xx
,&JTmp
,ODE_formula
,zofs
,bc
,DeviceDepth
);
1293 if(bc
[pzonedata
->electrode
[j
]].BCType
==SchottkyContact
)
1294 pzonedata
->F1E_mix_stk_electrode_Load(pzonedata
->electrode
[j
],PINinfos
[i
].I
,PINconds
[i
].pdI_pdV
,
1295 PINconds
[i
].pdI_pdw
,PINconds
[i
].pdF_pdV
,
1296 xx
,&JTmp
,ODE_formula
,zofs
,bc
,DeviceDepth
);
1297 if(bc
[pzonedata
->electrode
[j
]].BCType
==InsulatorContact
)
1298 pzonedata
->F1E_mix_ins_electrode_Load(pzonedata
->electrode
[j
],PINinfos
[i
].I
,PINconds
[i
].pdI_pdV
,
1299 PINconds
[i
].pdI_pdw
,PINconds
[i
].pdF_pdV
,
1300 xx
,&JTmp
,ODE_formula
,zofs
,bc
,DeviceDepth
);
1304 if(zonedata
[z
]->material_type
==Insulator
)
1306 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
1307 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
1308 if(bc
.is_electrode_label_nocase(pzonedata
->electrode
[j
], PINinfos
[i
].name
))
1310 pzonedata
->F1_mix_gate_electrode_Load(pzonedata
->electrode
[j
],PINinfos
[i
].I
,PINconds
[i
].pdI_pdV
,
1311 PINconds
[i
].pdI_pdw
,PINconds
[i
].pdF_pdV
,
1312 xx
,&J
,ODE_formula
,zofs
,bc
,DeviceDepth
);
1317 VecRestoreArray(x
,&xx
);
1319 //save conductance and rhs current source.
1320 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1323 for(int j
=0;j
<Deviceinfo
.term
;j
++)
1325 KSPSolve(ksp
,PINconds
[j
].pdF_pdV
,PINconds
[i
].pdw_pdV
);
1326 PetscScalar pdI_pdV
;
1327 VecDot(PINconds
[i
].pdI_pdw
,PINconds
[i
].pdw_pdV
,&pdI_pdV
);
1328 PINinfos
[i
].dI_dV
[j
] = pdI_pdV
;
1329 PINinfos
[i
].dI_dV
[j
] += PINconds
[i
].pdI_pdV
;
1330 PINinfos
[i
].dI_dV
[j
] /= scale_unit
.s_A
; //scale the element of dI/dV.
1331 Ig
+= PINinfos
[i
].dI_dV
[j
]*PINinfos
[j
].V
;
1333 PINinfos
[i
].I
= Ig
- PINinfos
[i
].I
/scale_unit
.s_A
;
1336 //sent conductance matrix and rhs current back to ngspice.
1337 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1338 send(client
,&PINinfos
[i
],sizeof(sPINinfo
),0);
1344 int DDM_Mix_Solver_L1E::DEV_ACCEPT()
1351 int DDM_Mix_Solver_L1E::DEV_CONV_TEST()
1353 CKTInfo
.convergence_flag
= reason
;
1354 send(client
,&(CKTInfo
),sizeof(sCKTinfo
),0);
1359 int DDM_Mix_Solver_L1E::tran_solve()
1361 PetscInt rework
= 1;
1362 PetscInt max_rework
= 64;
1363 PetscInt Converged
= 0;
1365 for(int i
=0;i
<zone_num
;i
++)
1366 if(zonedata
[i
]->material_type
== Semiconductor
)
1368 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
1369 pzonedata
->HighFieldMobility
= psv
->HighFieldMobility
;
1370 pzonedata
->ImpactIonization
= psv
->ImpactIonization
;
1371 pzonedata
->IIType
= psv
->IIType
;
1372 pzonedata
->BandBandTunneling
= psv
->BandBandTunneling
;
1373 pzonedata
->IncompleteIonization
= psv
->IncompleteIonization
;
1374 pzonedata
->QuantumMechanical
= psv
->QuantumMechanical
;
1375 pzonedata
->Fermi
= psv
->Fermi
;
1376 pzonedata
->EJModel
= psv
->EJModel
;
1381 reason
= SNES_CONVERGED_ITERATING
;
1382 for(int w
=1;w
<=rework
;w
++)
1384 ODE_formula
.dt
= w
*CKTInfo
.dt
*scale_unit
.s_second
/rework
;
1386 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1388 PetscScalar V_step
= PINinfos
[i
].V_old
+(PINinfos
[i
].V
-PINinfos
[i
].V_old
)*w
/rework
;
1389 bc
.Set_Vapp_nocase(PINinfos
[i
].name
,V_step
);
1392 SNESSolve(snes
,PETSC_NULL
,x
);
1393 SNESGetConvergedReason(snes
,&reason
);
1396 gss_log
.string_buf()<<"------> GSS mixed solver "<<SNESConvergedReasons
[reason
]<<", do recovery...\n\n\n";
1398 diverged_recovery();
1403 if(reason
>0) {Converged
= 1; break;}
1404 if(rework
>max_rework
) {Converged
= 0; break;}
1411 int DDM_Mix_Solver_L1E::dc_solve()
1413 PetscInt rework
= 1;
1414 PetscInt max_rework
= 64;
1415 PetscInt Converged
= 0;
1417 for(int i
=0;i
<zone_num
;i
++)
1418 if(zonedata
[i
]->material_type
== Semiconductor
)
1420 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
1421 pzonedata
->HighFieldMobility
= psv
->HighFieldMobility
;
1422 pzonedata
->ImpactIonization
= psv
->ImpactIonization
;
1423 pzonedata
->IIType
= psv
->IIType
;
1424 pzonedata
->BandBandTunneling
= psv
->BandBandTunneling
;
1425 pzonedata
->IncompleteIonization
= psv
->IncompleteIonization
;
1426 pzonedata
->QuantumMechanical
= psv
->QuantumMechanical
;
1427 pzonedata
->Fermi
= psv
->Fermi
;
1428 pzonedata
->EJModel
= psv
->EJModel
;
1433 reason
= SNES_CONVERGED_ITERATING
;
1434 for(int w
=1;w
<=rework
;w
++)
1436 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1438 PetscScalar V_step
= PINinfos
[i
].V_old
+(PINinfos
[i
].V
-PINinfos
[i
].V_old
)*w
/rework
;
1439 bc
.Set_Vapp_nocase(PINinfos
[i
].name
,V_step
);
1442 SNESSolve(snes
,PETSC_NULL
,x
);
1443 SNESGetConvergedReason(snes
,&reason
);
1446 gss_log
.string_buf()<<"------> GSS mixed solver "<<SNESConvergedReasons
[reason
]<<", do recovery...\n\n\n";
1448 diverged_recovery();
1453 if(reason
>0) {Converged
= 1; break;}
1454 if(rework
>max_rework
) {Converged
= 0; break;}
1461 /* ----------------------------------------------------------------------------
1462 * DDM_Mix_Solver_L1E::solution_update: This function restore solution data from SNES
1464 void DDM_Mix_Solver_L1E::solution_update()
1466 //------------------------------------------------------------
1470 for(int z
=0;z
<zone_num
;z
++)
1472 if(zonedata
[z
]->material_type
==Semiconductor
)
1474 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
1475 PetscScalar kb
= pzonedata
->mt
->kb
;
1476 PetscScalar e
= pzonedata
->mt
->e
;
1477 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1479 pzonedata
->fs
[i
].P_last
= pzonedata
->fs
[i
].P
;
1480 pzonedata
->fs
[i
].n_last
= pzonedata
->fs
[i
].n
;
1481 pzonedata
->fs
[i
].p_last
= pzonedata
->fs
[i
].p
;
1483 pzonedata
->fs
[i
].P
= xx
[offset
+0];
1484 pzonedata
->fs
[i
].n
= xx
[offset
+1];
1485 pzonedata
->fs
[i
].p
= xx
[offset
+2];
1487 pzonedata
->mt
->mapping(&pzonedata
->pzone
->danode
[i
],&pzonedata
->aux
[i
],0);
1488 PetscScalar nie
= pzonedata
->mt
->band
->nie(pzonedata
->fs
[i
].T
);
1489 pzonedata
->aux
[i
].phi_intrinsic
= pzonedata
->fs
[i
].P
+ pzonedata
->aux
[i
].affinity
+
1490 kb
*pzonedata
->fs
[i
].T
/e
*log(pzonedata
->aux
[i
].Nc
/nie
);
1491 pzonedata
->aux
[i
].phin
= pzonedata
->aux
[i
].phi_intrinsic
- log(fabs(pzonedata
->fs
[i
].n
)/nie
)*kb
*pzonedata
->fs
[i
].T
/e
;
1492 pzonedata
->aux
[i
].phip
= pzonedata
->aux
[i
].phi_intrinsic
+ log(fabs(pzonedata
->fs
[i
].p
)/nie
)*kb
*pzonedata
->fs
[i
].T
/e
;
1496 pzonedata
->F1E_efield_update(xx
,zofs
,bc
,zonedata
);
1497 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
1499 PetscScalar I
= bc
.Get_pointer(pzonedata
->electrode
[i
])->Get_Current_new();
1500 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Current(I
);
1503 if(zonedata
[z
]->material_type
==Insulator
)
1505 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
1506 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1508 pzonedata
->fs
[i
].P_last
= pzonedata
->fs
[i
].P
;
1509 pzonedata
->fs
[i
].P
= xx
[offset
];
1512 pzonedata
->F1_efield_update(xx
,zofs
,bc
,zonedata
);
1513 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
1515 PetscScalar I
= bc
.Get_pointer(pzonedata
->electrode
[i
])->Get_Current_new();
1516 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Current(I
);
1517 if(bc
[pzonedata
->electrode
[i
]].BCType
==ChargedContact
)
1518 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Potential(xx
[offset
]);
1522 if(zonedata
[z
]->material_type
==Conductor
)
1524 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
1525 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1527 pzonedata
->fs
[i
].P_last
= pzonedata
->fs
[i
].P
;
1528 pzonedata
->fs
[i
].P
= xx
[offset
];
1533 ODE_formula
.dt_last
= ODE_formula
.dt
;
1535 VecRestoreArray(x
,&xx
);
1539 /* ----------------------------------------------------------------------------
1540 * DDM_Mix_Solver_L1E::time_back_recovery: This function recovery latest solution data
1541 * if NGSPICE time drops back.
1543 void DDM_Mix_Solver_L1E::time_back_recovery()
1545 //------------------------------------------------------------
1549 for(int z
=0;z
<zone_num
;z
++)
1551 if(zonedata
[z
]->material_type
==Semiconductor
)
1553 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
1554 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1556 xx
[offset
+0] = pzonedata
->fs
[i
].P
;
1557 xx
[offset
+1] = pzonedata
->fs
[i
].n
;
1558 xx
[offset
+2] = pzonedata
->fs
[i
].p
;
1559 pzonedata
->fs
[i
].P
= pzonedata
->fs
[i
].P_last
;
1560 pzonedata
->fs
[i
].n
= pzonedata
->fs
[i
].n_last
;
1561 pzonedata
->fs
[i
].p
= pzonedata
->fs
[i
].p_last
;
1565 if(zonedata
[z
]->material_type
==Insulator
)
1567 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
1568 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1570 xx
[offset
] = pzonedata
->fs
[i
].P
;
1571 pzonedata
->fs
[i
].P
= pzonedata
->fs
[i
].P_last
;
1574 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
1576 if(bc
[pzonedata
->electrode
[i
]].BCType
==ChargedContact
)
1577 xx
[offset
] = bc
.Get_pointer(pzonedata
->electrode
[i
])->Get_Potential();
1583 if(zonedata
[z
]->material_type
==Conductor
)
1585 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
1586 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1588 xx
[offset
] = pzonedata
->fs
[i
].P
;
1589 pzonedata
->fs
[i
].P
= pzonedata
->fs
[i
].P_last
;
1594 VecRestoreArray(x
,&xx
);
1599 /* ----------------------------------------------------------------------------
1600 * DDM_Mix_Solver_L1E::diverged_recovery: This function recovery latest solution data
1603 void DDM_Mix_Solver_L1E::diverged_recovery()
1605 //------------------------------------------------------------
1609 for(int z
=0;z
<zone_num
;z
++)
1611 if(zonedata
[z
]->material_type
==Semiconductor
)
1613 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
1614 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1616 xx
[offset
+0] = pzonedata
->fs
[i
].P
;
1617 xx
[offset
+1] = pzonedata
->fs
[i
].n
;
1618 xx
[offset
+2] = pzonedata
->fs
[i
].p
;
1622 if(zonedata
[z
]->material_type
==Insulator
)
1624 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
1625 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1627 xx
[offset
] = pzonedata
->fs
[i
].P
;
1630 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
1632 if(bc
[pzonedata
->electrode
[i
]].BCType
==ChargedContact
)
1633 xx
[offset
] = bc
.Get_pointer(pzonedata
->electrode
[i
])->Get_Potential();
1639 if(zonedata
[z
]->material_type
==Conductor
)
1641 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
1642 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
1644 xx
[offset
] = pzonedata
->fs
[i
].P
;
1649 VecRestoreArray(x
,&xx
);
1653 /* ----------------------------------------------------------------------------
1654 * DDM_Mix_Solver_L1E::destroy_solver: This function do destroy the nonlinear solver
1656 int DDM_Mix_Solver_L1E::destroy_solver(SolveDefine
&sv
)
1661 for(int i
=0;i
<Deviceinfo
.term
;i
++)
1663 VecDestroy(PINconds
[i
].pdI_pdw
);
1664 VecDestroy(PINconds
[i
].pdF_pdV
);
1665 VecDestroy(PINconds
[i
].pdw_pdV
);