1 /*****************************************************************************/
2 /* 8888888 88888888 88888888 */
5 /* 8 88888888 88888888 */
8 /* 888888 888888888 888888888 */
10 /* A Two-Dimensional General Purpose Semiconductor Simulator. */
13 /* Last update: Nov 19, 2006 */
17 /* NINT, No.69 P.O.Box, Xi'an City, China */
19 /*****************************************************************************/
22 #include "ddm_nt1ac.h"
25 /* ----------------------------------------------------------------------------
26 * DDM_Solver_L1AC::form_linear_system_ac1: This function build the linear system.
28 void DDM_Solver_L1AC::form_linear_system_ac1(PetscScalar omega
, PetscScalar
*x
, Mat
*jac
, Vec
*r
, Mat
*jtmp
)
33 //Compute complex Jacobian matrix and right vector.
34 for(int z
=0;z
<zone_num
;z
++)
36 if(zonedata
[z
]->material_type
==Semiconductor
)
38 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
41 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
43 if(bc
[pzonedata
->electrode
[i
]].BCType
==OhmicContact
)
44 pzonedata
->AC1_om_electrode(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
,DeviceDepth
);
45 if(bc
[pzonedata
->electrode
[i
]].BCType
==SchottkyContact
)
46 pzonedata
->AC1_stk_electrode(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
,DeviceDepth
);
47 if(bc
[pzonedata
->electrode
[i
]].BCType
==InsulatorContact
)
48 pzonedata
->AC1_ins_electrode(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
,DeviceDepth
);
51 // process cell variables and boundaries.
52 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
54 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
55 SemiData
*pfs
= &pzonedata
->fs
[i
];
56 if(!pcell
->bc_index
||bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
57 pzonedata
->AC1_ddm_inner(i
,omega
,x
,jac
,r
,&JTmp
,zofs
);
58 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==OhmicContact
)
59 pzonedata
->AC1_ddm_ombc(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
);
60 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==SchottkyContact
)
61 pzonedata
->AC1_ddm_stkbc(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
);
62 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorContact
)
63 pzonedata
->AC1_ddm_insulator_gate(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
);
64 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorInterface
)
66 InsulatorInterfaceBC
*pbc
;
67 pbc
= dynamic_cast<InsulatorInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
68 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
69 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
70 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
71 pzonedata
->AC1_ddm_interface(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
,pz
,n_node
);
73 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==HomoInterface
)
76 pbc
= dynamic_cast<HomoInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
77 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
78 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
79 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
80 pzonedata
->AC1_ddm_homojunction(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
,pz
,n_node
);
82 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==HeteroInterface
)
84 HeteroInterfaceBC
*pbc
;
85 pbc
= dynamic_cast<HeteroInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
86 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
87 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
88 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
89 pzonedata
->AC1_ddm_heterojunction(i
,omega
,x
,jac
,r
,&JTmp
,zofs
,bc
,pz
,n_node
);
92 pzonedata
->AC1_ddm_inner(i
,omega
,x
,jac
,r
,&JTmp
,zofs
);
97 if(zonedata
[z
]->material_type
==Insulator
)
99 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
100 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
102 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
103 if(!pcell
->bc_index
||bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
104 pzonedata
->AC1_ddm_inner(i
,omega
,x
,r
,jac
,zofs
);
105 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==GateContact
)
106 pzonedata
->AC1_ddm_gatebc(i
,omega
,x
,r
,jac
,zofs
,bc
);
107 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==ChargedContact
)
108 pzonedata
->AC1_ddm_chargebc(i
,omega
,x
,r
,jac
,zofs
,bc
);
109 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Electrode_Insulator
)
111 ElectrodeInsulatorBC
*pbc
;
112 pbc
= dynamic_cast<ElectrodeInsulatorBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
113 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
114 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
115 ElZone
* pz
= dynamic_cast<ElZone
*>(zonedata
[n_zone
]);
116 pzonedata
->AC1_ddm_electrode_insulator_interface(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
118 else if(pcell
->bc_index
&&bc
[pcell
->bc_index
-1].BCType
==InsulatorInterface
)
120 InsulatorInterfaceBC
*pbc
;
121 pbc
= dynamic_cast<InsulatorInterfaceBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
122 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
123 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
124 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
125 pzonedata
->AC1_ddm_semiconductor_insulator_interface(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
127 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Insulator_Insulator
)
129 InsulatorInsulatorBC
*pbc
;
130 pbc
= dynamic_cast<InsulatorInsulatorBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
131 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
132 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
133 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
134 pzonedata
->AC1_ddm_insulator_insulator_interface(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
137 pzonedata
->AC1_ddm_inner(i
,omega
,x
,r
,jac
,zofs
);
139 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
141 if(bc
[pzonedata
->electrode
[i
]].BCType
==GateContact
)
142 pzonedata
->AC1_gate_electrode(i
,omega
,x
,r
,jac
,zofs
,bc
,DeviceDepth
);
143 if(bc
[pzonedata
->electrode
[i
]].BCType
==ChargedContact
)
144 pzonedata
->AC1_charge_electrode(i
,omega
,x
,r
,jac
,zofs
,bc
);
149 if(zonedata
[z
]->material_type
==Conductor
)
151 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
152 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
154 const VoronoiCell
* pcell
= zone
[z
].davcell
.GetPointer(i
);
155 if(!pcell
->bc_index
|| bc
[pcell
->bc_index
-1].BCType
==NeumannBoundary
)
156 pzonedata
->AC1_ddm_inner(i
,omega
,x
,r
,jac
,zofs
);
157 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==IF_Electrode_Insulator
)
158 pzonedata
->AC1_ddm_inner(i
,omega
,x
,r
,jac
,zofs
);
159 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==OhmicContact
)
161 OhmicBC
*pbc
= dynamic_cast<OhmicBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
162 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
163 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
164 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
165 pzonedata
->AC1_ddm_om_contact(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
167 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==SchottkyContact
)
169 SchottkyBC
*pbc
= dynamic_cast<SchottkyBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
170 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
171 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
172 SMCZone
* pz
= dynamic_cast<SMCZone
*>(zonedata
[n_zone
]);
173 pzonedata
->AC1_ddm_stk_contact(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
175 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==GateContact
)
177 GateBC
*pbc
= dynamic_cast<GateBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
178 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
179 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
180 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
181 pzonedata
->AC1_ddm_gate_contact(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
183 else if(pcell
->bc_index
&& bc
[pcell
->bc_index
-1].BCType
==ChargedContact
)
185 ChargedContactBC
*pbc
= dynamic_cast<ChargedContactBC
*>(bc
.Get_pointer(pcell
->bc_index
-1));
186 int n_zone
= pbc
->pinterface
->Find_neighbor_zone_index(z
);
187 int n_node
= pbc
->pinterface
->Find_neighbor_node_index(z
,i
);
188 ISZone
* pz
= dynamic_cast<ISZone
*>(zonedata
[n_zone
]);
189 pzonedata
->AC1_ddm_charge_contact(i
,omega
,x
,r
,jac
,zofs
,bc
,pz
,n_node
);
192 pzonedata
->AC1_ddm_inner(i
,omega
,x
,r
,jac
,zofs
);
197 MatAssemblyBegin(*jac
,MAT_FINAL_ASSEMBLY
);
198 MatAssemblyEnd(*jac
,MAT_FINAL_ASSEMBLY
);
199 VecAssemblyBegin(*r
);
204 /* ----------------------------------------------------------------------------
205 * DDM_Solver_L1AC::Get_Jacobian: This function get a real Jacobian matrix.
207 void DDM_Solver_L1AC::Get_Jacobian()
209 // compute the scale of JTmp
210 zofs
.resize(zone_num
+1);
213 for(int i
=0;i
<zone_num
;i
++)
215 if(zonedata
[i
]->material_type
==Semiconductor
) //semiconductor zone
217 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
218 N
+= 3*pzonedata
->pzone
->davcell
.size();
219 N
+= pzonedata
->electrode
.size(); //additional equation for electrode
222 else if(zonedata
[i
]->material_type
==Insulator
) //Insulator zone
224 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[i
]);
225 N
+= pzonedata
->pzone
->davcell
.size();
226 N
+= pzonedata
->electrode
.size(); //additional equation for electrode
229 else if(zonedata
[i
]->material_type
==Conductor
) //Electrode zone
231 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[i
]);
232 N
+= pzonedata
->pzone
->davcell
.size();
235 else //other zones, such as PML and vacuum
240 // create DC solution array v
241 x
= new PetscScalar
[N
];
242 // fill initial value
244 for(int z
=0;z
<zone_num
;z
++)
246 if(zonedata
[z
]->material_type
==Semiconductor
)
248 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
249 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
251 x
[offset
+0] = pzonedata
->fs
[i
].P
;
252 x
[offset
+1] = pzonedata
->fs
[i
].n
;
253 x
[offset
+2] = pzonedata
->fs
[i
].p
;
256 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
258 PetscScalar P
= bc
.Get_pointer(pzonedata
->electrode
[j
])->Get_Potential();
264 if(zonedata
[z
]->material_type
==Insulator
)
266 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
267 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
269 x
[offset
+0] = pzonedata
->fs
[i
].P
;
272 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
274 PetscScalar P
= bc
.Get_pointer(pzonedata
->electrode
[j
])->Get_Potential();
279 if(zonedata
[z
]->material_type
==Conductor
)
281 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[z
]);
282 for(int i
=0;i
<zone
[z
].davcell
.size();i
++)
284 x
[offset
+0] = pzonedata
->fs
[i
].P
;
289 // Create Jacobian matrix data structure
290 // pre-alloc approximate memory
291 int *nnz
= new int[N
];
293 for(int i
=0;i
<zone_num
;i
++)
296 if(zonedata
[i
]->material_type
==Semiconductor
)
298 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
299 for(int j
=0;j
<pzonedata
->pzone
->davcell
.size();j
++)
301 const VoronoiCell
* pcell
= pzonedata
->pzone
->davcell
.GetPointer(j
);
302 //inner node, alloc exact memory.
303 if(!pcell
->bc_index
|| bc
[pcell
->bc_index
-1].psegment
->interface
==-1)
305 *p
++ = 3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
306 *p
++ = 3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
307 *p
++ = 3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
309 else //interface node, slightly more than needed.
311 *p
++ = 3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
312 *p
++ = 3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
313 *p
++ = 3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
316 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
318 *p
++ = bc
[pzonedata
->electrode
[j
]].psegment
->node_array
.size()+1;
322 //Insulator zones, poisson equation only
323 if(zonedata
[i
]->material_type
==Insulator
)
325 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[i
]);
326 for(int j
=0;j
<zone
[i
].davcell
.size();j
++)
328 *p
++ = zone
[i
].davcell
[j
].nb_num
+1;
330 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
332 *p
++ = bc
[pzonedata
->electrode
[j
]].psegment
->node_array
.size()+1;
335 //Electrode zones, poisson equation only
336 if(zonedata
[i
]->material_type
==Conductor
)
338 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[i
]);
339 for(int j
=0;j
<zone
[i
].davcell
.size();j
++)
340 *p
++ = 1*(zone
[i
].davcell
[j
].nb_num
+1);
343 MatCreateSeqAIJ(PETSC_COMM_SELF
,N
,N
,0,nnz
,&JTmp
);
345 //Compute Jacobian entries for flux along triangle edges.
346 for(int z
=0;z
<zone_num
;z
++)
348 if(zonedata
[z
]->material_type
==Semiconductor
)
350 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
351 // compute flux Jacobian along triangle edges
352 for(int i
=0;i
<zone
[z
].datri
.size();i
++)
354 Tri
*ptri
= &zone
[z
].datri
[i
];
355 pzonedata
->J1E_Tri_ddm(ptri
,x
,&JTmp
,zofs
);
359 MatAssemblyBegin(JTmp
,MAT_FINAL_ASSEMBLY
);
360 MatAssemblyEnd(JTmp
,MAT_FINAL_ASSEMBLY
);
365 /* ----------------------------------------------------------------------------
366 * DDM_Solver_L1AC::init_solver: This function do initial setup for AC linear solver
368 int DDM_Solver_L1AC::init_solver(SolveDefine
&sv
)
370 gss_log
.string_buf()<<"DDM solver Level 1 AC Sweep init...";
372 //distable advaced features.
373 for(int i
=0;i
<zone_num
;i
++)
374 if(zonedata
[i
]->material_type
== Semiconductor
)
376 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
377 pzonedata
->HighFieldMobility
= sv
.HighFieldMobility
;
378 pzonedata
->ImpactIonization
= sv
.ImpactIonization
;
379 pzonedata
->IIType
= sv
.IIType
;
380 pzonedata
->BandBandTunneling
= sv
.BandBandTunneling
;
381 pzonedata
->IncompleteIonization
= sv
.IncompleteIonization
;
382 pzonedata
->QuantumMechanical
= sv
.QuantumMechanical
;
383 pzonedata
->Fermi
= sv
.Fermi
;
384 pzonedata
->EJModel
= sv
.EJModel
;
389 // scale of complex Jac
390 VecCreateSeq(PETSC_COMM_SELF
,2*N
,&v
);
393 // Create Jacobian matrix data structure
394 // pre-alloc approximate memory
395 int *nnz
= new int[2*N
];
397 //fill half of the array nnz
398 for(int i
=0;i
<zone_num
;i
++)
401 if(zonedata
[i
]->material_type
==Semiconductor
)
403 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
404 for(int j
=0;j
<pzonedata
->pzone
->davcell
.size();j
++)
406 const VoronoiCell
* pcell
= pzonedata
->pzone
->davcell
.GetPointer(j
);
407 //inner node, alloc exact memory.
408 if(!pcell
->bc_index
|| bc
[pcell
->bc_index
-1].psegment
->interface
==-1)
410 *p
++ = 2*3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
411 *p
++ = 2*3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
412 *p
++ = 2*3*(pzonedata
->pzone
->davcell
[j
].nb_num
+1);
414 else //interface node, slightly more than needed.
416 *p
++ = 2*3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
417 *p
++ = 2*3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
418 *p
++ = 2*3*(2*pzonedata
->pzone
->davcell
[j
].nb_num
+4);
421 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
423 *p
++ = 2*(bc
[pzonedata
->electrode
[j
]].psegment
->node_array
.size()+1);
427 //Insulator zones, poisson equation only
428 if(zonedata
[i
]->material_type
==Insulator
)
430 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[i
]);
431 for(int j
=0;j
<zone
[i
].davcell
.size();j
++)
433 *p
++ = 2*(zone
[i
].davcell
[j
].nb_num
+1);
435 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
437 *p
++ = 2*(bc
[pzonedata
->electrode
[j
]].psegment
->node_array
.size()+1);
440 //Electrode zones, poisson equation only
441 if(zonedata
[i
]->material_type
==Conductor
)
443 ElZone
*pzonedata
= dynamic_cast< ElZone
* >(zonedata
[i
]);
444 for(int j
=0;j
<zone
[i
].davcell
.size();j
++)
445 *p
++ = 2*(zone
[i
].davcell
[j
].nb_num
+1);
449 //fill another half of nnz array
453 MatCreate(PETSC_COMM_SELF
,&J
);
454 MatSetSizes(J
,2*N
,2*N
,2*N
,2*N
);
457 #ifdef PETSC_HAVE_SUPERLU
458 MatSetType(J
,MATSUPERLU
);
460 MatSetType(J
,MATSEQAIJ
);
463 else if(sv
.LS
=="umfpack")
465 #ifdef PETSC_HAVE_UMFPACK
466 MatSetType(J
,MATUMFPACK
);
468 MatSetType(J
,MATSEQAIJ
);
473 MatSetType(J
,MATSEQAIJ
);
475 MatSeqAIJSetPreallocation(J
,0,nnz
);
477 //MatCreateSeqAIJ(PETSC_COMM_SELF,2*N,2*N,0,nnz,&J);
480 KSPCreate(PETSC_COMM_SELF
,&ksp
);
481 KSPSetOperators(ksp
,J
,J
,SAME_NONZERO_PATTERN
);
483 //KSPSetMonitor(ksp,KSPDefaultMonitor,PETSC_NULL,PETSC_NULL);
484 if(sv
.LS
=="lu"||sv
.LS
=="superlu"||sv
.LS
=="umfpack")
486 KSPSetType(ksp
,KSPGMRES
);
487 KSPSetTolerances(ksp
,1e-20*N
,1e-18*N
,PETSC_DEFAULT
,N
/2);
489 PCFactorSetReuseOrdering(pc
,PETSC_TRUE
);
490 PCFactorSetPivoting(pc
,1.0);
491 PCFactorReorderForNonzeroDiagonal(pc
,1e-14);
492 PCFactorSetShiftNonzero(pc
,1e-12);
496 KSPSetType(ksp
,sv
.LS
.c_str());
497 if(sv
.LS
=="gmres") KSPGMRESSetRestart(ksp
,150);
498 KSPSetTolerances(ksp
,1e-20*N
,1e-18*N
,PETSC_DEFAULT
,max(35,N
/2));
500 PCFactorSetLevels(pc
,3);
501 PCFactorSetShiftNonzero(pc
,1e-14);
502 PCFactorReorderForNonzeroDiagonal(pc
,1e-12);
504 KSPSetFromOptions(ksp
);
505 gss_log
.string_buf()<<"done\n";
511 /* ----------------------------------------------------------------------------
512 * DDM_Solver_L1AC::do_solve: This function solve the problem
514 int DDM_Solver_L1AC::do_solve(SolveDefine
&sv
)
520 gss_log
.string_buf()<<"DDML1AC not support this solver type!\n";
527 /* ----------------------------------------------------------------------------
528 * DDM_Solver_L1AC::solve_ac: This function compute device response to
529 * small AC signal AC.
531 int DDM_Solver_L1AC::solve_ac(SolveDefine
&sv
)
534 PetscScalar current_scale_mA
= scale_unit
.s_mA
;
535 PetscScalar voltage_scale_V
=scale_unit
.s_volt
;
536 KSPConvergedReason reason
;
542 //set which electrodes are required to record IV
543 for(int i
=0;i
<zone_num
;i
++)
545 if(zonedata
[i
]->material_type
== Semiconductor
)
547 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[i
]);
548 pzonedata
->ImpactIonization
= sv
.ImpactIonization
;
549 pzonedata
->IncompleteIonization
= sv
.IncompleteIonization
;
550 pzonedata
->QuantumMechanical
= sv
.QuantumMechanical
;
551 for(int k
=0;k
<sv
.Electrode_Record_Name
.size();k
++)
552 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
554 if(bc
.is_electrode_label(pzonedata
->electrode
[j
], sv
.Electrode_Record_Name
[k
].c_str()))
555 sv
.Electrode_Record
.push_back(pzonedata
->electrode
[j
]);
558 if(zonedata
[i
]->material_type
== Insulator
)
560 ISZone
* pzonedata
= dynamic_cast< ISZone
* >(zonedata
[i
]);
561 for(int k
=0;k
<sv
.Electrode_Record_Name
.size();k
++)
562 for(int j
=0;j
<pzonedata
->electrode
.size();j
++)
564 if(bc
.is_electrode_label(pzonedata
->electrode
[j
], sv
.Electrode_Record_Name
[k
].c_str()))
565 sv
.Electrode_Record
.push_back(pzonedata
->electrode
[j
]);
570 // output DC Scan information
571 gss_log
.string_buf()<<"AC scan from "<<sv
.FStart
*scale_unit
.s_second
/1e6
572 <<" MHz step size "<<sv
.FMultiple
573 <<" to "<<sv
.FStop
*scale_unit
.s_second
/1e6
<<" MHz"<<"\n";
576 // prepare IV file. If no file given, output to screen.
577 if(!sv
.IVFile
.empty())
579 fiv
=fopen(sv
.IVFile
.c_str(),"w");
581 fprintf(fiv
,"Freq[MHz] ");
582 for(int j
=0;j
<sv
.Electrode_Record
.size();j
++)
583 fprintf(fiv
,"Vp(%s)[V] I(%s)[mA] ",
584 sv
.Electrode_Record_Name
[j
].c_str(),
585 sv
.Electrode_Record_Name
[j
].c_str()
593 PetscScalar omega
= 2*PI
*sv
.FStart
;
596 gss_log
.string_buf()<<"The start frequency shouldn't be zero or negtive.\n";
601 bc
.Set_electrode_type(sv
.Electrode_ACScan_Name
.c_str(),VoltageBC
);
602 bc
.Set_Vac(sv
.Electrode_ACScan_Name
.c_str(),sv
.VAC
);
604 while( omega
< 2*PI
*sv
.FStop
)
606 gss_log
.string_buf()<<"AC Scan: f("<<sv
.Electrode_ACScan_Name
<<") = "
607 <<omega
/(2*PI
)*scale_unit
.s_second
/1e6
<<" MHz "<<"\n";
609 form_linear_system_ac1(omega
,x
,&J
,&r
,&JTmp
);
612 KSPGetConvergedReason(ksp
,&reason
);
613 KSPGetIterationNumber(ksp
,&its
);
614 KSPGetResidualNorm(ksp
,&rnorm
);
615 gss_log
.string_buf()<<"------> residual norm = "<<rnorm
<<" its = "<<its
<<" with "<<SNESConvergedReasons
[reason
]<<"\n\n";
617 compute_electrode_current(omega
);
618 fprintf(fiv
,"%e\t",double(omega
/(2*PI
)*scale_unit
.s_second
/1e6
));
619 for(int j
=0;j
<sv
.Electrode_Record
.size();j
++)
621 int zone_index
= bc
[sv
.Electrode_Record
[j
]].psegment
->zone_index
;
622 complex<PetscScalar
> I
= bc
.Get_pointer(sv
.Electrode_Record
[j
])->Get_Iac()/current_scale_mA
;
623 complex<PetscScalar
> P
= bc
.Get_pointer(sv
.Electrode_Record
[j
])->Get_Pac()/voltage_scale_V
;
624 fprintf(fiv
,"%e %e %e\t %e %e %e\t",
625 double(P
.real()),double(P
.imag()),double(abs(P
)),
626 double(I
.real()),double(I
.imag()),double(abs(I
)));
633 if(!sv
.IVFile
.empty()) fclose(fiv
);
638 /* ----------------------------------------------------------------------------
639 * DDM_Solver_L1AC::compute_electrode_current: This function compute electrode current after
642 void DDM_Solver_L1AC::compute_electrode_current(PetscScalar omega
)
644 //------------------------------------------------------------
648 for(int z
=0;z
<zone_num
;z
++)
650 if(zonedata
[z
]->material_type
==Semiconductor
)
652 SMCZone
*pzonedata
= dynamic_cast< SMCZone
* >(zonedata
[z
]);
654 int size
= pzonedata
->pzone
->davcell
.size();
655 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
657 PetscScalar IacRe
=0,IacIm
=0;
658 PetscScalar PRe
= vv
[zofs
[z
]+size
*equ_num
+i
];
659 PetscScalar PIm
= vv
[N
+zofs
[z
]+size
*equ_num
+i
];
661 if(bc
[pzonedata
->electrode
[i
]].BCType
==OhmicContact
)
662 pzonedata
->AC1_om_electrode_current(i
,omega
,x
,&v
,&JTmp
, zofs
, bc
, DeviceDepth
, IacRe
, IacIm
);
663 if(bc
[pzonedata
->electrode
[i
]].BCType
==SchottkyContact
)
664 pzonedata
->AC1_stk_electrode_current(i
,omega
,x
,&v
,&JTmp
, zofs
, bc
, DeviceDepth
, IacRe
, IacIm
);
665 if(bc
[pzonedata
->electrode
[i
]].BCType
==InsulatorContact
)
666 pzonedata
->AC1_ins_electrode_current(i
,omega
,x
,&v
,&JTmp
, zofs
, bc
, DeviceDepth
, IacRe
, IacIm
);
667 complex<PetscScalar
> I(IacRe
,IacIm
);
668 complex<PetscScalar
> P(PRe
,PIm
);
669 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Iac(I
);
670 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Pac(P
);
674 if(zonedata
[z
]->material_type
==Insulator
)
676 ISZone
*pzonedata
= dynamic_cast< ISZone
* >(zonedata
[z
]);
678 int size
= pzonedata
->pzone
->davcell
.size();
679 for(int i
=0;i
<pzonedata
->electrode
.size();i
++)
681 PetscScalar IacRe
=0,IacIm
=0;
682 PetscScalar PRe
= vv
[zofs
[z
]+size
*equ_num
+i
];
683 PetscScalar PIm
= vv
[N
+zofs
[z
]+size
*equ_num
+i
];
684 if(bc
[pzonedata
->electrode
[i
]].BCType
==GateContact
)
685 pzonedata
->AC1_gate_electrode_current(i
,omega
,x
,&v
,zofs
, bc
, DeviceDepth
, IacRe
, IacIm
);
686 complex<PetscScalar
> I(IacRe
,IacIm
);
687 complex<PetscScalar
> P(PRe
,PIm
);
688 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Iac(I
);
689 bc
.Get_pointer(pzonedata
->electrode
[i
])->Set_Pac(P
);
694 VecRestoreArray(v
,&vv
);
698 /* ----------------------------------------------------------------------------
699 * DDM_Solver_L1AC::destroy_solver: This function do destroy the nonlinear solver
701 int DDM_Solver_L1AC::destroy_solver(SolveDefine
&sv
)