Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
uvahotspot
GitHub Repository: uvahotspot/HotSpot
Path: blob/master/temperature_grid.c
612 views
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#ifdef _MSC_VER
5
#define strcasecmp _stricmp
6
#define strncasecmp _strnicmp
7
#else
8
#include <strings.h>
9
#endif
10
#include <math.h>
11
12
#include "temperature_grid.h"
13
#include "flp.h"
14
#include "util.h"
15
#include "microchannel.h"
16
17
// export some of the matrices into CSV files
18
// WARNING : only use for small designs, as the files get prohibitively large easily
19
#define MAKE_CSVS 0
20
21
#if SUPERLU > 0
22
/* Lib for SuperLU */
23
#include "slu_ddefs.h"
24
#endif
25
26
double find_res(grid_model_t *model, int n1, int i1, int j1, int n2, int i2, int j2) {
27
double res;
28
29
// Testing using Heat Transfer Coefficient instead of thermal conductivities
30
31
double htc = 0.0;
32
double cw = model->width / model->cols;
33
double ch = model->height / model->rows;
34
double extra_res = 0;
35
36
// Whether or not Cell 1 or Cell 2 is a fluid cell
37
int is_fluid_cell1 = 0, is_fluid_cell2 = 0;
38
if(model->layers[n1].is_microchannel) {
39
htc = model->layers[n1].microchannel_config->htc;
40
if(IS_FLUID_CELL(model->layers[n1].microchannel_config, i1, j1))
41
is_fluid_cell1 = 1;
42
else
43
is_fluid_cell1 = 0;
44
}
45
else
46
is_fluid_cell1 = 0;
47
48
if(model->layers[n2].is_microchannel) {
49
htc = model->layers[n2].microchannel_config->htc;
50
if(IS_FLUID_CELL(model->layers[n2].microchannel_config, i2, j2))
51
is_fluid_cell2 = 1;
52
else
53
is_fluid_cell2 = 0;
54
}
55
else
56
is_fluid_cell2 = 0;
57
58
59
//fprintf(stderr, "htc = %e\n", htc);
60
// If one cell is a fluid cell and the other isn't, use HTC instead
61
if((is_fluid_cell1 && !is_fluid_cell2) || (!is_fluid_cell1 && is_fluid_cell2)) {
62
if(n1 == 0) {
63
// We know that n2 must be the fluid cell
64
res = find_res_3D(n1, i1, j1, model, 3) + (1.0 / (htc * ch * cw)) + extra_res;
65
//fprintf(stderr, "Res (%d, %d, %d) -> (%d, %d, %d) = %e\n", n1, i1, j1, n2, i2, j2, res);
66
}
67
else if(n2 == 0) {
68
// We know that n1 must be the fluid cell
69
res = find_res_3D(n2, i2, j2, model, 3) + (1.0 / (htc * ch * cw)) + extra_res;
70
//fprintf(stderr, "Res (%d, %d, %d) -> (%d, %d, %d) = %e\n", n1, i1, j1, n2, i2, j2, res);
71
}
72
else if(n1 != n2 && i1 == i2 && j1 == j2) {
73
if(is_fluid_cell1)
74
res = (find_res_3D(n2, i2, j2, model, 3) / 2.0) + (1.0 / (htc * ch * cw)) + extra_res;
75
else
76
res = (find_res_3D(n1, i1, j1, model, 3) / 2.0) + (1.0 / (htc * ch * cw)) + extra_res;
77
//fprintf(stderr, "Res (%d, %d, %d) -> (%d, %d, %d) = %e\n", n1, i1, j1, n2, i2, j2, res);
78
}
79
else if(n1 == n2 && i1 != i2 && j1 == j2) {
80
if(is_fluid_cell1)
81
res = (find_res_3D(n2, i2, j2, model, 1) / 2.0) + (1.0 / (htc * cw * model->layers[n1].thickness));
82
else
83
res = (find_res_3D(n1, i1, j1, model, 1) / 2.0) + (1.0 / (htc * cw * model->layers[n2].thickness));
84
//fprintf(stderr, "Res (%d, %d, %d) -> (%d, %d, %d) = %e\n", n1, i1, j1, n2, i2, j2, res);
85
}
86
else if(n1 == n2 && i1 == i2 && j1 != j2) {
87
if(is_fluid_cell1)
88
res = (find_res_3D(n2, i2, j2, model, 2) / 2.0) + (1.0 / (htc * ch * model->layers[n1].thickness));
89
else
90
res = (find_res_3D(n1, i1, j1, model, 2) / 2.0) + (1.0 / (htc * ch * model->layers[n2].thickness));
91
//fprintf(stderr, "Res (%d, %d, %d) -> (%d, %d, %d) = %e\n", n1, i1, j1, n2, i2, j2, res);
92
}
93
else {
94
fatal("find_res must be called on adjacent grid cells\n");
95
}
96
}
97
else if(model->config.detailed_3D_used == 1) {
98
if(n1 == 0 && i1 == i2 && j1 == j2) {
99
res = find_res_3D(n1, i1, j1, model, 3) + (find_res_3D(n2, i2, j2, model, 3) / 2.0);
100
}
101
else if(n2 == 0 && i1 == i2 && j1 == j2)
102
res = find_res_3D(n2, i2, j2, model, 3) + (find_res_3D(n1, i1, j1, model, 3) / 2.0);
103
else if(n1 != n2 && i1 == i2 && j1 == j2) {
104
res = (find_res_3D(n1, i1, j1, model, 3) / 2.0) + (find_res_3D(n2, i2, j2, model, 3) / 2.0);
105
}
106
else if(n1 == n2 && i1 != i2 && j1 == j2) {
107
res = (find_res_3D(n1, i1, j1, model, 1) / 2.0) + (find_res_3D(n2, i2, j2, model, 1) / 2.0);
108
}
109
else if(n1 == n2 && i1 == i2 && j1 != j2) {
110
res = (find_res_3D(n1, i1, j1, model, 2) / 2.0) + (find_res_3D(n2, i2, j2, model, 2) / 2.0);
111
}
112
else {
113
fatal("find_res must be called on adjacent grid cells\n");
114
}
115
}
116
else {
117
if(n1 < n2 && i1 == i2 && j1 == j2) {
118
res = model->layers[n1].rz;
119
}
120
else if(n1 > n2 && i1 == i2 && j1 == j2) {
121
res = model->layers[n2].rz;
122
}
123
else if(n1 == n2 && i1 != i2 && j1 == j2) {
124
res = (model->layers[n1].rx / 2.0) + (model->layers[n2].rx / 2.0);
125
}
126
else if(n1 == n2 && i1 == i2 && j1 != j2) {
127
res = (model->layers[n1].ry / 2.0) + (model->layers[n2].ry / 2.0);
128
}
129
else {
130
fatal("find_res must be called on adjacent grid cells\n");
131
}
132
}
133
134
//fprintf(stderr, "Cell (%d, %d, %d) to Cell (%d, %d, %d) : %e\n", n1, i1, j2, n2, i2, j2, res);
135
return res;
136
}
137
138
139
/*BU_3D: We modified R-C computations to return resistance or capacitance for a specified grid cell.
140
* If the grid cell does not have a unique value assigned in the flp file, we return the default values
141
* for that layer.the find_res_3D function will return the rx,ry,rz value of the grid.
142
* This function is used with the macros later.
143
* It will calculate the joint resistance only if there are values defined within the array or rx,ry,rz values. */
144
double find_res_3D(int n, int i, int j, grid_model_t *model,int choice)
145
{
146
int hasRes = model->layers[n].b2gmap[i][j]->hasRes;
147
//Returns the rx of the grid cell
148
if(choice==1){
149
if(!hasRes)
150
return model->layers[n].rx;
151
else
152
return model->layers[n].b2gmap[i][j]->rx;
153
154
}
155
156
//Returns the ry of the grid cell
157
else if(choice==2){
158
if(!hasRes)
159
return model->layers[n].ry;
160
else
161
return model->layers[n].b2gmap[i][j]->ry;
162
}
163
164
//Returns the rz of the grid cell
165
else if(choice==3){
166
if(!hasRes)
167
return model->layers[n].rz;
168
else
169
return model->layers[n].b2gmap[i][j]->rz;
170
}
171
172
return 0;
173
}//end->BU_3D
174
175
/* BU_3D: finds capacitance of 3D cell.*/
176
double find_cap_3D(int n, int i, int j, grid_model_t *model)
177
{
178
if (model->layers[n].b2gmap[i][j]->lock == TRUE) {
179
// Return the capacitance of the unit that meets the occupancy threshold
180
return model->layers[n].b2gmap[i][j]->capacitance;
181
} else {
182
// No unit that meets the occupancy threshold.
183
// Return the layer's (default) capacitance instead
184
return model->layers[n].c;
185
}
186
}//end->BU_3D
187
188
/* constructors */
189
/*BU_3D:
190
* - Added parameter do_detailed_3D to this function
191
* - Assign grid specific resistivty and capacitance if unit occupying the grid have resistivity & capacitance values
192
* - If occupancy is > OCCUPANCY_THRESHOLD% then use the values obtained from the resistivity & capacitance of the occupying unit */
193
blist_t *new_blist(int idx, double occupancy, double res, double specificHeat,int first,int do_detailed_3D, double cw, double ch, double thickness)
194
{
195
blist_t *ptr = (blist_t *) calloc (1, sizeof(blist_t));
196
if (!ptr)
197
fatal("memory allocation error\n");
198
ptr->idx = idx;
199
ptr->occupancy = occupancy;
200
ptr->next = NULL;
201
/*BU_3D:
202
* - If occupancy is greater than OCCUPANCY_THRESHOLD% lock in thermal resistance values
203
* - Else assume 50/50 occupancy*/
204
if(first && do_detailed_3D){
205
if(occupancy >= OCCUPANCY_THRESHOLD){
206
ptr->lock=TRUE;
207
ptr->rx = getr(1/res, cw, ch * thickness);
208
ptr->ry = getr(1/res, ch, cw * thickness);
209
ptr->rz = getr(1/res, thickness, cw * ch);
210
ptr->capacitance = getcap(specificHeat, thickness, cw * ch);
211
//fprintf(stderr, "1/res = %e, cw = %e, ch = %e, thickness = %e, occupancy = %e\n", 1/res, cw, ch, thickness, occupancy);
212
}
213
else{
214
ptr->lock=FALSE;
215
ptr->rx = 1 / ((1 / getr(1 / res, cw, ch * thickness)) * occupancy);
216
ptr->ry = 1 / ((1 / getr(1 / res, ch, cw * thickness)) * occupancy);
217
ptr->rz = 1 / ((1 / getr(1 / res, thickness, cw * ch)) * occupancy);
218
ptr->capacitance = getcap(specificHeat, thickness, cw * ch);
219
}
220
return ptr;
221
}
222
/*end->BU_3D*/
223
return ptr;
224
}
225
226
blist_t ***new_b2gmap(int rows, int cols)
227
{
228
int i;
229
blist_t ***b2gmap;
230
231
b2gmap = (blist_t ***) calloc (rows, sizeof(blist_t **));
232
b2gmap[0] = (blist_t **) calloc (rows * cols, sizeof(blist_t *));
233
if (!b2gmap || !b2gmap[0])
234
fatal("memory allocation error\n");
235
236
for(i=1; i < rows; i++)
237
b2gmap[i] = b2gmap[0] + cols * i;
238
239
return b2gmap;
240
}
241
242
243
/* destructor */
244
void delete_b2gmap(blist_t ***b2gmap, int rows, int cols)
245
{
246
int i, j;
247
blist_t *ptr, *temp;
248
249
/* free the linked list */
250
for(i=0; i < rows; i++)
251
for(j=0; j < cols; j++) {
252
ptr = b2gmap[i][j];
253
while(ptr) {
254
temp = ptr->next;
255
free(ptr);
256
ptr = temp;
257
}
258
}
259
260
/* free the array space */
261
free(b2gmap[0]);
262
free(b2gmap);
263
}
264
265
/* re-initialize */
266
void reset_b2gmap(grid_model_t *model, layer_t *layer)
267
{
268
int i, j;
269
blist_t *ptr, *temp;
270
271
/* free the linked list */
272
for(i=0; i < model->rows; i++)
273
for(j=0; j < model->cols; j++) {
274
ptr = layer->b2gmap[i][j];
275
while(ptr) {
276
temp = ptr->next;
277
free(ptr);
278
ptr = temp;
279
}
280
layer->b2gmap[i][j] = NULL;
281
}
282
}
283
284
/* create a linked list node and append it at the end
285
* BU_3D: The parameter int do_detailed_3D is added to this function*/
286
void blist_append(blist_t *head, int idx, double occupancy,double res, double specificHeat,int first, int do_detailed_3D,double cw, double ch, double thickness)
287
{
288
/*BU_3D:
289
* - If a block occupies a grid cell by OCCUPANCY_THRESHOLD% or more, the grid cell gets that blocks thermal resistance values
290
* otherwise, 50/50 sharing is assumed with whichever block is occupying the other portion.
291
* - Add resistances in parallel */
292
if(do_detailed_3D && (head->lock!=TRUE)){
293
if(occupancy >= OCCUPANCY_THRESHOLD){
294
head->lock=TRUE;
295
head->rx = getr(1/res, cw, ch * thickness);
296
head->ry = getr(1/res, ch, cw * thickness);
297
head->rz = getr(1/res, thickness, cw * ch);
298
head->capacitance = getcap(specificHeat, thickness, cw * ch);
299
}
300
else{
301
head->rx = 1/((1/head->rx) + ((1 / getr(1 / res, cw, ch * thickness)) * occupancy));
302
head->ry = 1/((1/head->ry) + ((1 / getr(1 / res, ch, cw * thickness)) * occupancy));
303
head->rz = 1/((1/head->rz) + ((1 / getr(1 / res, thickness, cw * ch)) * occupancy));
304
head->lock=FALSE;
305
}
306
}
307
/*end->BU_3D*/
308
blist_t *tail = NULL;
309
310
if(!head)
311
fatal("blist_append called with empty list\n");
312
313
/* traverse till the end */
314
for(; head; head = head->next)
315
tail = head;
316
317
/* append
318
* BU_3D: added do_detailed_3D to this function call*/
319
tail->next = new_blist(idx, occupancy, res, specificHeat, first, do_detailed_3D, cw, ch, thickness);
320
}
321
322
/* compute the power/temperature average weighted by occupancies */
323
double blist_avg(blist_t *ptr, flp_t *flp, double *v, int type)
324
{
325
double val = 0.0;
326
327
for(; ptr; ptr = ptr->next) {
328
if (type == V_POWER)
329
val += ptr->occupancy * v[ptr->idx] / (flp->units[ptr->idx].width *
330
flp->units[ptr->idx].height);
331
else if (type == V_TEMP)
332
val += ptr->occupancy * v[ptr->idx];
333
else
334
fatal("unknown vector type\n");
335
}
336
337
return val;
338
}
339
340
/* setup the block and grid mapping data structures */
341
void set_bgmap(grid_model_t *model, layer_t *layer)
342
{
343
/* i1, i2, j1 and j2 are indices of the boundary grid cells */
344
int i, j, u, i1, i2, j1, j2;
345
346
/* shortcuts for cell width(cw) and cell height(ch) */
347
double cw = model->width / model->cols;
348
double ch = model->height / model->rows;
349
/* shortcut for unit resistivity & specific heat*/
350
double sh,res;
351
/* initialize */
352
reset_b2gmap(model, layer);
353
354
/* for each functional unit */
355
for(u=0; u < layer->flp->n_units; u++) {
356
/* shortcuts for unit boundaries */
357
double lu = layer->flp->units[u].leftx;
358
double ru = lu + layer->flp->units[u].width;
359
double bu = layer->flp->units[u].bottomy;
360
double tu = bu + layer->flp->units[u].height;
361
362
/* top index (lesser row) = rows - ceil (topy / cell height) */
363
i1 = model->rows - tolerant_ceil(tu/ch);
364
/* bottom index (greater row) = rows - floor (bottomy / cell height) */
365
i2 = model->rows - tolerant_floor(bu/ch);
366
/* left index = floor (leftx / cell width) */
367
j1 = tolerant_floor(lu/cw);
368
/* right index = ceil (rightx / cell width) */
369
j2 = tolerant_ceil(ru/cw);
370
/* sanity check */
371
if((i1 < 0) || (j1 < 0))
372
fatal("negative grid cell start index!\n");
373
if((i2 > model->rows) || (j2 > model->cols))
374
fatal("grid cell end index out of bounds!\n");
375
if((i1 >= i2) || (j1 >= j2))
376
fatal("invalid floorplan spec or grid resolution\n");
377
378
/* setup g2bmap */
379
layer->g2bmap[u].i1 = i1;
380
layer->g2bmap[u].i2 = i2;
381
layer->g2bmap[u].j1 = j1;
382
layer->g2bmap[u].j2 = j2;
383
384
/* setup b2gmap */
385
/* for each grid cell in this unit */
386
for(i=i1; i < i2; i++) {
387
for(j=j1; j < j2; j++) {
388
/* grid cells fully overlapped by this unit */
389
390
/*BU_3D*/
391
// - Load values from floorplan into each grid
392
if(layer->flp->units[u].hasRes && model->config.detailed_3D_used)
393
res = layer->flp->units[u].resistivity;
394
else
395
res = 1/layer->k;
396
if(layer->flp->units[u].hasSh && model->config.detailed_3D_used)
397
sh = layer->flp->units[u].specificheat;
398
else
399
sh = layer->sp;
400
/*end->BU_3D*/
401
402
if ((i > i1) && (i < i2-1) && (j > j1) && (j < j2-1)) {
403
/* first unit in the list */
404
if (!layer->b2gmap[i][j]){
405
layer->b2gmap[i][j] = new_blist(u, 1.0,res,sh,1,model->config.detailed_3D_used,cw,ch,layer->thickness);
406
layer->b2gmap[i][j]->hasRes = TRUE;//BU_3D assign hasRes to the b2gdata structure
407
layer->b2gmap[i][j]->hasCap = layer->flp->units[u].hasSh;//BU_3D assign hasSh to the b2gdata structure
408
}
409
else {
410
/* this should not occur since the grid cell is
411
* fully covered and hence, no other unit should
412
* be sharing it */
413
blist_append(layer->b2gmap[i][j], u, 1.0,res,sh,1,model->config.detailed_3D_used,cw,ch,layer->thickness);
414
warning("overlap of functional blocks?\n");
415
}
416
/* boundary grid cells partially overlapped by this unit */
417
} else {
418
/* shortcuts for cell boundaries */
419
double lc = j * cw, rc = (j+1) * cw;
420
double tc = model->height - i * ch;
421
double bc = model->height - (i+1) * ch;
422
423
/* shortcuts for overlap width and height */
424
double oh = (MIN(tu, tc) - MAX(bu, bc));
425
double ow = (MIN(ru, rc) - MAX(lu, lc));
426
double occupancy;
427
428
/* overlap tolerance */
429
if (eq(oh/ch, 0))
430
oh = 0;
431
else if (eq(oh/ch, 1))
432
oh = ch;
433
434
if (eq(ow/cw, 0))
435
ow = 0;
436
else if (eq(ow/cw, 1))
437
ow = cw;
438
439
occupancy = (oh * ow) / (ch * cw);
440
if (oh < 0 || ow < 0)
441
fatal("negative overlap!\n");
442
443
/* first unit in the list */
444
if (!layer->b2gmap[i][j]){
445
layer->b2gmap[i][j] = new_blist(u, occupancy,res,sh,1,model->config.detailed_3D_used,cw,ch,layer->thickness);
446
layer->b2gmap[i][j]->hasRes = TRUE;//BU_3D assign hasRes to the b2gdata structure
447
layer->b2gmap[i][j]->hasCap = layer->flp->units[u].hasSh;//BU_3D assign hasSh to the b2gdata structure
448
}
449
else
450
/* append at the end */
451
blist_append(layer->b2gmap[i][j], u, occupancy,res,sh,0,model->config.detailed_3D_used,cw,ch,layer->thickness);
452
}
453
}
454
}
455
}
456
}
457
458
/* populate default set of layers */
459
void populate_default_layers(grid_model_t *model, flp_t *flp_default)
460
{
461
int silidx, intidx, metalidx, c4idx;
462
463
if (!model->config.model_secondary) {
464
silidx = LAYER_SI;
465
intidx = LAYER_INT;
466
} else {
467
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
468
intidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_INT;
469
c4idx = SEC_PACK_LAYERS + LAYER_C4;
470
metalidx = SEC_PACK_LAYERS + LAYER_METAL;
471
}
472
473
/* silicon */
474
model->layers[silidx].no = silidx;
475
model->layers[silidx].has_lateral = TRUE;
476
model->layers[silidx].has_power = TRUE;
477
model->layers[silidx].k = model->config.k_chip;
478
model->layers[silidx].thickness = model->config.t_chip;
479
model->layers[silidx].sp = model->config.p_chip;
480
model->layers[silidx].flp = flp_default;
481
model->layers[silidx].b2gmap = new_b2gmap(model->rows, model->cols);
482
model->layers[silidx].g2bmap = (glist_t *) calloc(flp_default->n_units, sizeof(glist_t));
483
if (!model->layers[silidx].g2bmap)
484
fatal("memory allocation error\n");
485
486
/* interface material */
487
model->layers[intidx].no = intidx;
488
model->layers[intidx].has_lateral = TRUE;
489
model->layers[intidx].has_power = FALSE;
490
model->layers[intidx].k = model->config.k_interface;
491
model->layers[intidx].thickness = model->config.t_interface;
492
model->layers[intidx].sp = model->config.p_interface;
493
model->layers[intidx].flp = flp_default;
494
model->layers[intidx].b2gmap = model->layers[silidx].b2gmap;
495
model->layers[intidx].g2bmap = model->layers[silidx].g2bmap;
496
497
if (model->config.model_secondary) {
498
/* metal layer */
499
model->layers[metalidx].no = metalidx;
500
model->layers[metalidx].has_lateral = TRUE;
501
model->layers[metalidx].has_power = FALSE;
502
model->layers[metalidx].k = K_METAL;
503
model->layers[metalidx].thickness = model->config.t_metal;
504
model->layers[metalidx].sp = SPEC_HEAT_METAL;
505
model->layers[metalidx].flp = flp_default;
506
model->layers[metalidx].b2gmap = model->layers[silidx].b2gmap;
507
model->layers[metalidx].g2bmap = model->layers[silidx].g2bmap;
508
509
/* C4/underfill layer*/
510
model->layers[c4idx].no = c4idx;
511
model->layers[c4idx].has_lateral = TRUE;
512
model->layers[c4idx].has_power = FALSE;
513
model->layers[c4idx].k = K_C4;
514
model->layers[c4idx].thickness = model->config.t_c4;
515
model->layers[c4idx].sp = SPEC_HEAT_C4;
516
model->layers[c4idx].flp = flp_default;
517
model->layers[c4idx].b2gmap = model->layers[silidx].b2gmap;
518
model->layers[c4idx].g2bmap = model->layers[silidx].g2bmap;
519
}
520
}
521
522
/* populate the package layers */
523
void append_package_layers(grid_model_t *model)
524
{
525
/* shortcut */
526
int nl = model->n_layers;
527
int silidx, spidx, hsidx, subidx, solderidx, pcbidx;
528
529
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
530
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
531
532
/* spreader */
533
model->layers[spidx].no = spidx;
534
model->layers[spidx].has_lateral = TRUE;
535
model->layers[spidx].has_power = FALSE;
536
model->layers[spidx].k = model->config.k_spreader;
537
model->layers[spidx].thickness = model->config.t_spreader;
538
model->layers[spidx].sp = model->config.p_spreader;
539
model->layers[spidx].flp = model->layers[spidx-1].flp;
540
model->layers[spidx].b2gmap = model->layers[spidx-1].b2gmap;
541
model->layers[spidx].g2bmap = model->layers[spidx-1].g2bmap;
542
543
/* heatsink */
544
model->layers[hsidx].no = hsidx;
545
model->layers[hsidx].has_lateral = TRUE;
546
model->layers[hsidx].has_power = FALSE;
547
model->layers[hsidx].k = model->config.k_sink;
548
model->layers[hsidx].thickness = model->config.t_sink;
549
model->layers[hsidx].sp = model->config.p_sink;
550
model->layers[hsidx].flp = model->layers[spidx-1].flp;
551
model->layers[hsidx].b2gmap = model->layers[spidx-1].b2gmap;
552
model->layers[hsidx].g2bmap = model->layers[spidx-1].g2bmap;
553
554
/* BU_3D: If detailed_3d option is on, the hasRes & hasCap variables must be set false in the b2gmap*/
555
if(model->config.detailed_3D_used){
556
model->layers[spidx].b2gmap = new_b2gmap(model->rows, model->cols);
557
model->layers[hsidx].b2gmap = model->layers[spidx].b2gmap;
558
}
559
/*end->BU_3D*/
560
561
if (model->config.model_secondary) {
562
if(model->has_lcf)
563
silidx = SEC_PACK_LAYERS;
564
else
565
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
566
subidx = LAYER_SUB;
567
solderidx = LAYER_SOLDER;
568
pcbidx = LAYER_PCB;
569
570
/* package substrate */
571
model->layers[subidx].no = subidx;
572
model->layers[subidx].has_lateral = TRUE;
573
model->layers[subidx].has_power = FALSE;
574
model->layers[subidx].k = K_SUB;
575
model->layers[subidx].thickness = model->config.t_sub;
576
model->layers[subidx].sp = SPEC_HEAT_SUB;
577
model->layers[subidx].flp = model->layers[silidx].flp;
578
model->layers[subidx].b2gmap = model->layers[silidx].b2gmap;
579
model->layers[subidx].g2bmap = model->layers[silidx].g2bmap;
580
581
/* solder balls */
582
model->layers[solderidx].no = solderidx;
583
model->layers[solderidx].has_lateral = TRUE;
584
model->layers[solderidx].has_power = FALSE;
585
model->layers[solderidx].k = K_SOLDER;
586
model->layers[solderidx].thickness = model->config.t_solder;
587
model->layers[solderidx].sp = SPEC_HEAT_SOLDER;
588
model->layers[solderidx].flp = model->layers[silidx].flp;
589
model->layers[solderidx].b2gmap = model->layers[silidx].b2gmap;
590
model->layers[solderidx].g2bmap = model->layers[silidx].g2bmap;
591
592
/* PCB */
593
model->layers[pcbidx].no = pcbidx;
594
model->layers[pcbidx].has_lateral = TRUE;
595
model->layers[pcbidx].has_power = FALSE;
596
model->layers[pcbidx].k = K_PCB;
597
model->layers[pcbidx].thickness = model->config.t_pcb;
598
model->layers[pcbidx].sp = SPEC_HEAT_PCB;
599
model->layers[pcbidx].flp = model->layers[silidx].flp;
600
model->layers[pcbidx].b2gmap = model->layers[silidx].b2gmap;
601
model->layers[pcbidx].g2bmap = model->layers[silidx].g2bmap;
602
603
if(model->config.detailed_3D_used){
604
model->layers[subidx].b2gmap = new_b2gmap(model->rows, model->cols);
605
model->layers[solderidx].b2gmap = model->layers[subidx].b2gmap;
606
model->layers[pcbidx].b2gmap = model->layers[subidx].b2gmap;
607
}
608
}
609
}
610
611
/* parse the layer file open for reading */
612
void parse_layer_file(grid_model_t *model, FILE *fp, materials_list_t *materials_list)
613
{
614
char line[LINE_SIZE], *ptr, cval;
615
int count, i = 0, field = LCF_SNO, ival;
616
double dval;
617
int base, inner_layers;
618
619
if (!model->config.model_secondary){
620
base = 0;
621
inner_layers = model->n_layers - DEFAULT_PACK_LAYERS;
622
}
623
else{
624
base = SEC_PACK_LAYERS;
625
inner_layers = model->n_layers - DEFAULT_PACK_LAYERS - SEC_PACK_LAYERS;
626
}
627
628
fseek(fp, 0, SEEK_SET);
629
count = 0;
630
while (!feof(fp)) {
631
fgets(line, LINE_SIZE, fp);
632
if (feof(fp))
633
break;
634
635
/* ignore comments and empty lines */
636
ptr = strtok(line, " \r\t\n");
637
if (!ptr || ptr[0] == '#')
638
continue;
639
640
switch (field)
641
{
642
case LCF_SNO:
643
if (sscanf(ptr, "%d", &ival) != 1)
644
fatal("invalid layer number\n");
645
if(ival >= inner_layers || ival < 0)
646
fatal("layer number must be >= 0 and < no. of layers specified\n");
647
if (model->layers[base+ival].no != 0)
648
fatal("layer numbers must be unique\n");
649
i = base + ival;
650
model->layers[i].no = base + ival;
651
field = LCF_LATERAL;
652
break;
653
case LCF_LATERAL:
654
if (sscanf(ptr, "%c", &cval) != 1)
655
fatal("invalid layer heat flow indicator\n");
656
if (cval == 'Y' || cval == 'y')
657
model->layers[i].has_lateral = TRUE;
658
else if (cval == 'N' || cval == 'n')
659
model->layers[i].has_lateral = FALSE;
660
else
661
fatal("invalid layer heat flow indicator\n");
662
field = LCF_POWER;
663
break;
664
case LCF_POWER:
665
if (sscanf(ptr, "%c", &cval) != 1)
666
fatal("invalid layer power dissipation indicator\n");
667
if (cval == 'Y' || cval == 'y')
668
model->layers[i].has_power = TRUE;
669
else if (cval == 'N' || cval == 'n')
670
model->layers[i].has_power = FALSE;
671
else
672
fatal("invalid layer power dissipation indicator\n");
673
field = LCF_SP;
674
break;
675
case LCF_SP:
676
if (sscanf(ptr, "%lf", &dval) != 1) {
677
// check if material was specified instead
678
char material_name[STR_SIZE];
679
if(sscanf(ptr, "%s", material_name) != 1)
680
fatal("invalid: neither specific heat nor material name was specified\n");
681
682
model->layers[i].sp = get_material_volumetric_heat_capacity(materials_list, material_name);
683
model->layers[i].k = get_material_thermal_conductivity(materials_list, material_name);
684
field = LCF_THICK;
685
break;
686
}
687
else {
688
model->layers[i].sp = dval;
689
field = LCF_RHO;
690
break;
691
}
692
case LCF_RHO:
693
if (sscanf(ptr, "%lf", &dval) != 1)
694
fatal("invalid resistivity\n");
695
model->layers[i].k = 1.0 / dval;
696
field = LCF_THICK;
697
break;
698
case LCF_THICK:
699
if (sscanf(ptr, "%lf", &dval) != 1)
700
fatal("invalid thickness\n");
701
model->layers[i].thickness = dval;
702
field = LCF_FLP;
703
break;
704
case LCF_FLP:
705
/* Check if layer is a microchannel layer */
706
if(strstr(ptr, NETWORK_EXTENSION) && model->use_microchannels) {
707
model->layers[i].is_microchannel = TRUE;
708
model->layers[i].microchannel_config = malloc(sizeof(microchannel_config_t));
709
710
// Copy over user-defined parameters
711
copy_microchannel(model->layers[i].microchannel_config, model->default_microchannel_config);
712
713
// Fill in parameters derived from model
714
model->layers[i].microchannel_config->cell_width = model->width / model->cols;
715
model->layers[i].microchannel_config->cell_height = model->height / model->rows;
716
model->layers[i].microchannel_config->cell_thickness = model->layers[i].thickness;
717
model->layers[i].microchannel_config->num_rows = model->rows;
718
model->layers[i].microchannel_config->num_columns = model->cols;
719
720
// Fill in network file from LCF
721
strcpy(model->layers[i].microchannel_config->network_file, ptr);
722
723
// Build internal representation of microchannel network and create
724
// floorplan
725
microchannel_build_network(model->layers[i].microchannel_config);
726
model->layers[i].flp = read_flp(model->layers[i].microchannel_config->floorplan_file, FALSE, FALSE);
727
}
728
else if(strstr(ptr, NETWORK_EXTENSION) && !model->use_microchannels) {
729
fatal("Floorplan file has microchannel extension but use_microchannels = 0\n");
730
}
731
else {
732
model->layers[i].flp = read_flp(ptr, FALSE, FALSE);
733
model->layers[i].is_microchannel = FALSE;
734
}
735
736
/* first layer */
737
if (count < LCF_NPARAMS) {
738
model->width = get_total_width(model->layers[i].flp);
739
model->height = get_total_height(model->layers[i].flp);
740
} else if(!eq(model->width, get_total_width(model->layers[i].flp)) ||
741
!eq(model->height, get_total_height(model->layers[i].flp)))
742
fatal("width and height differ across layers\n");
743
field = LCF_SNO;
744
break;
745
default:
746
fatal("invalid field id\n");
747
break;
748
}
749
count++;
750
}
751
752
/* allocate the block-grid maps */
753
for(i=base; i < (base+inner_layers); i++) {
754
model->layers[i].b2gmap = new_b2gmap(model->rows, model->cols);
755
model->layers[i].g2bmap = (glist_t *) calloc(model->layers[i].flp->n_units,
756
sizeof(glist_t));
757
if (!model->layers[i].g2bmap)
758
fatal("memory allocation error\n");
759
}
760
}
761
762
/* count number of layers in LCF file and make sure the basic formatting is correct */
763
int count_num_layers(FILE *fp) {
764
char line[LINE_SIZE], *ptr, cval, sval[STR_SIZE];
765
int ival, number_layers = 0, field = LCF_SNO;
766
double dval;
767
768
fseek(fp, 0, SEEK_SET);
769
while (!feof(fp)) {
770
fgets(line, LINE_SIZE, fp);
771
if (feof(fp))
772
break;
773
774
/* ignore comments and empty lines */
775
ptr = strtok(line, " \r\t\n");
776
if (!ptr || ptr[0] == '#')
777
continue;
778
779
switch (field) {
780
case LCF_SNO:
781
if (sscanf(ptr, "%d", &ival) != 1)
782
fatal("invalid layer number\n");
783
field = LCF_LATERAL;
784
break;
785
case LCF_LATERAL:
786
if (sscanf(ptr, "%c", &cval) != 1)
787
fatal("invalid layer heat flow indicator\n");
788
field = LCF_POWER;
789
break;
790
case LCF_POWER:
791
if (sscanf(ptr, "%c", &cval) != 1)
792
fatal("invalid layer power dissipation indicator\n");
793
field = LCF_SP;
794
break;
795
case LCF_SP:
796
if (sscanf(ptr, "%lf", &dval) != 1) {
797
// check if material was specified instead
798
if(sscanf(ptr, "%s", sval) != 1)
799
fatal("invalid: neither specific heat nor material name was specified\n");
800
801
field = LCF_THICK;
802
break;
803
}
804
else {
805
field = LCF_RHO;
806
break;
807
}
808
case LCF_RHO:
809
if (sscanf(ptr, "%lf", &dval) != 1)
810
fatal("invalid resistivity\n");
811
field = LCF_THICK;
812
break;
813
case LCF_THICK:
814
if (sscanf(ptr, "%lf", &dval) != 1)
815
fatal("invalid thickness\n");
816
field = LCF_FLP;
817
break;
818
case LCF_FLP:
819
if(sscanf(ptr, "%s", sval) != 1)
820
fatal("invalid floorplan file");
821
number_layers++;
822
field = LCF_SNO;
823
break;
824
default:
825
fatal("invalid field id\n");
826
break;
827
}
828
}
829
return number_layers;
830
}
831
832
/* populate layer info either from the default floorplan or from
833
* the layer configuration file (lcf)
834
*/
835
void populate_layers_grid(grid_model_t *model, flp_t *flp_default, materials_list_t *materials_list)
836
{
837
char str[STR_SIZE];
838
FILE *fp = NULL;
839
840
/* lcf file specified */
841
if (model->has_lcf) {
842
if (!strcasecmp(model->config.grid_layer_file, "stdin"))
843
fp = stdin;
844
else
845
fp = fopen (model->config.grid_layer_file, "r");
846
if (!fp) {
847
strncpy(str, "Unable to open file ", STR_SIZE);
848
strncat(str, model->config.grid_layer_file, STR_SIZE - strlen(str));
849
strncat(str, "\n", STR_SIZE - strlen(str));
850
fatal(str);
851
}
852
}
853
854
/* compute the no. of layers */
855
if (!model->config.model_secondary) {
856
if (model->has_lcf) {
857
model->n_layers = count_num_layers(fp);
858
} else
859
model->n_layers = DEFAULT_CHIP_LAYERS;
860
} else {
861
if (model->has_lcf) {
862
model->n_layers = count_num_layers(fp);
863
} else
864
model->n_layers = DEFAULT_CHIP_LAYERS + SEC_CHIP_LAYERS;
865
}
866
867
/* allocate initial memory including package layers */
868
if (!model->config.model_secondary) {
869
model->n_layers += DEFAULT_PACK_LAYERS;
870
model->layers = (layer_t *) calloc (model->n_layers, sizeof(layer_t));
871
if (!model->layers)
872
fatal("memory allocation error\n");
873
} else {
874
model->n_layers += DEFAULT_PACK_LAYERS + SEC_PACK_LAYERS;
875
model->layers = (layer_t *) calloc (model->n_layers, sizeof(layer_t));
876
if (!model->layers)
877
fatal("memory allocation error\n");
878
}
879
880
/* read in values from the lcf when specified */
881
if (model->has_lcf) {
882
parse_layer_file(model, fp, materials_list);
883
} else {
884
/* default set of layers */
885
populate_default_layers(model, flp_default);
886
}
887
888
/* append the package layers */
889
append_package_layers(model);
890
891
if (model->has_lcf && fp != stdin)
892
fclose(fp);
893
}
894
895
/* constructor */
896
grid_model_t *alloc_grid_model(thermal_config_t *config, flp_t *flp_default, microchannel_config_t *microchannel_config, materials_list_t *materials_list, int do_detailed_3D, int use_microchannels)
897
{
898
int i;
899
grid_model_t *model;
900
901
#if SUPERLU < 1
902
if (config->grid_rows & (config->grid_rows-1) ||
903
config->grid_cols & (config->grid_cols-1))
904
fatal("grid rows and columns should both be powers of two\n");
905
#endif
906
907
model = (grid_model_t *) calloc (1, sizeof(grid_model_t));
908
if (!model)
909
fatal("memory allocation error\n");
910
model->config = *config;
911
model->rows = config->grid_rows;
912
model->cols = config->grid_cols;
913
model->use_microchannels = use_microchannels;
914
model->default_microchannel_config = microchannel_config;
915
if(do_detailed_3D) //BU_3D: check if heterogenous RC model is on
916
model->config.detailed_3D_used = TRUE;
917
if(!strcasecmp(model->config.grid_map_mode, GRID_AVG_STR))
918
model->map_mode = GRID_AVG;
919
else if(!strcasecmp(model->config.grid_map_mode, GRID_MIN_STR))
920
model->map_mode = GRID_MIN;
921
else if(!strcasecmp(model->config.grid_map_mode, GRID_MAX_STR))
922
model->map_mode = GRID_MAX;
923
else if(!strcasecmp(model->config.grid_map_mode, GRID_CENTER_STR))
924
model->map_mode = GRID_CENTER;
925
else
926
fatal("unknown mapping mode\n");
927
928
/* layer configuration file specified? */
929
if(strcmp(model->config.grid_layer_file, NULLFILE))
930
model->has_lcf = TRUE;
931
else {
932
model->has_lcf = FALSE;
933
model->base_n_units = flp_default->n_units;
934
}
935
936
/* get layer information */
937
populate_layers_grid(model, flp_default, materials_list);
938
/* count the total no. of blocks */
939
model->total_n_blocks = 0;
940
for(i=0; i < model->n_layers; i++)
941
model->total_n_blocks += model->layers[i].flp->n_units;
942
943
/* allocate internal state */
944
model->last_steady = new_grid_model_vector(model);
945
model->last_trans = new_grid_model_vector(model);
946
947
return model;
948
}
949
950
void populate_R_model_grid(grid_model_t *model, flp_t *flp)
951
{
952
int i, base;
953
double cw, ch;
954
955
int inner_layers;
956
int silidx, hsidx;
957
int model_secondary = model->config.model_secondary;
958
int nl = model->n_layers;
959
960
if(model_secondary){
961
if(model->has_lcf){
962
base = SEC_PACK_LAYERS;
963
inner_layers = nl - DEFAULT_PACK_LAYERS - SEC_PACK_LAYERS;
964
silidx = SEC_PACK_LAYERS + LAYER_SI;
965
}
966
else{
967
base = SEC_CHIP_LAYERS + SEC_PACK_LAYERS;
968
inner_layers = nl - DEFAULT_PACK_LAYERS - SEC_PACK_LAYERS - SEC_CHIP_LAYERS;
969
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
970
}
971
}
972
else{
973
base = 0;
974
inner_layers = nl - DEFAULT_PACK_LAYERS;
975
silidx = LAYER_SI;
976
}
977
978
/* setup the block-grid maps; flp parameter is ignored */
979
if(model->has_lcf)
980
for(i=base; i < (base+inner_layers); i++){
981
set_bgmap(model, &model->layers[i]);
982
}
983
/* only the silicon layer has allocated space for the maps.
984
* all the rest just point to it. so it is sufficient to
985
* setup the block-grid map for the silicon layer alone.
986
* further, for default layer configuration, the `flp'
987
* parameter should be the same as that of the silicon
988
* layer. finally, the chip width and height information
989
* need to be populated for default layer configuration
990
*/
991
else {
992
if (flp != model->layers[silidx].flp)
993
fatal("mismatch between the floorplan and the thermal model\n");
994
model->width = get_total_width(flp);
995
model->height = get_total_height(flp);
996
set_bgmap(model, &model->layers[silidx]);
997
}
998
999
/* BU_3D: If detailed 3D is used we need to set variables in the b2gmap of the spreader layer*/
1000
if(model->config.detailed_3D_used){
1001
int ii,jj;
1002
int spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
1003
set_bgmap(model, &model->layers[spidx]);
1004
for(ii=0; ii < model->rows; ii++)
1005
for(jj=0; jj < model->cols; jj++){
1006
/* Make hasRes & hasCap as false*/
1007
model->layers[spidx].b2gmap[ii][jj]->hasRes = FALSE;
1008
model->layers[spidx].b2gmap[ii][jj]->hasCap = FALSE;
1009
model->layers[spidx].b2gmap[ii][jj]->lock = FALSE;
1010
}
1011
if(model_secondary){
1012
int subidx = LAYER_SUB;
1013
set_bgmap(model, &model->layers[subidx]);
1014
for(ii=0; ii < model->rows; ii++)
1015
for(jj=0; jj < model->cols; jj++){
1016
/* Make hasRes & hasCap as false*/
1017
model->layers[subidx].b2gmap[ii][jj]->hasRes = FALSE;
1018
model->layers[subidx].b2gmap[ii][jj]->hasCap = FALSE;
1019
model->layers[subidx].b2gmap[ii][jj]->lock = FALSE;
1020
}
1021
}
1022
} //end->BU_3D
1023
1024
/* sanity check on floorplan sizes */
1025
if (model->width > model->config.s_sink ||
1026
model->height > model->config.s_sink ||
1027
model->width > model->config.s_spreader ||
1028
model->height > model->config.s_spreader) {
1029
print_flp(model->layers[silidx].flp, FALSE);
1030
print_flp_fig(model->layers[silidx].flp);
1031
fatal("inordinate floorplan size!\n");
1032
}
1033
1034
/* shortcuts for cell width(cw) and cell height(ch) */
1035
cw = model->width / model->cols;
1036
ch = model->height / model->rows;
1037
1038
/* package R's */
1039
populate_package_R(&model->pack, &model->config, model->width, model->height);
1040
1041
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
1042
/* layer specific resistances */
1043
for(i=0; i < model->n_layers; i++){
1044
if (model->layers[i].has_lateral) {
1045
model->layers[i].rx = getr(model->layers[i].k, cw, ch * model->layers[i].thickness);
1046
model->layers[i].ry = getr(model->layers[i].k, ch, cw * model->layers[i].thickness);
1047
} else {
1048
/* positive infinity */
1049
model->layers[i].rx = LARGENUM;
1050
model->layers[i].ry = LARGENUM;
1051
}
1052
model->layers[i].rz = getr(model->layers[i].k, model->layers[i].thickness, cw * ch);
1053
1054
/* heatsink is connected to ambient. divide r_convec proportional to cell area */
1055
if (i == hsidx){
1056
model->layers[i].rz += model->config.r_convec *
1057
(model->config.s_sink * model->config.s_sink) / (cw * ch);
1058
}
1059
}
1060
1061
/* done */
1062
model->r_ready = TRUE;
1063
}
1064
1065
void populate_C_model_grid(grid_model_t *model, flp_t *flp)
1066
{
1067
int i;
1068
int silidx, hsidx, pcbidx;
1069
1070
/* shortcuts */
1071
double cw = model->width / model->cols;
1072
double ch = model->height / model->rows;
1073
int nl = model->n_layers;
1074
int model_secondary = model->config.model_secondary;
1075
1076
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
1077
if(model_secondary){
1078
if(model->has_lcf)
1079
silidx = SEC_PACK_LAYERS + LAYER_SI;
1080
else
1081
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
1082
1083
pcbidx = LAYER_PCB;
1084
}
1085
else{
1086
silidx = LAYER_SI;
1087
}
1088
1089
if (!model->r_ready)
1090
fatal("R model not ready\n");
1091
if (!model->has_lcf && flp != model->layers[silidx].flp)
1092
fatal("different floorplans for R and C models!\n");
1093
1094
/* package C's */
1095
populate_package_C(&model->pack, &model->config, model->width, model->height);
1096
1097
/* layer specific capacitances */
1098
for(i=0; i < nl; i++){
1099
model->layers[i].c = getcap(model->layers[i].sp, model->layers[i].thickness, cw * ch);
1100
}
1101
1102
/* last layer (heatsink) is connected to the ambient.
1103
* divide c_convec proportional to cell area
1104
*/
1105
model->layers[hsidx].c += C_FACTOR * model->config.c_convec * (cw * ch) / \
1106
(model->config.s_sink * model->config.s_sink);
1107
if (model_secondary) {
1108
model->layers[pcbidx].c += C_FACTOR * model->config.c_convec_sec * (cw * ch) / \
1109
(model->config.s_pcb * model->config.s_pcb);
1110
}
1111
1112
/* done */
1113
model->c_ready = TRUE;
1114
}
1115
1116
/* destructor */
1117
void delete_grid_model(grid_model_t *model)
1118
{
1119
int i, base;
1120
int inner_layers;
1121
int silidx;
1122
int model_secondary = model->config.model_secondary;
1123
int nl = model->n_layers;
1124
1125
if (model_secondary){
1126
if(model->has_lcf){
1127
base = SEC_PACK_LAYERS;
1128
inner_layers = nl - DEFAULT_PACK_LAYERS - SEC_PACK_LAYERS;
1129
silidx = SEC_PACK_LAYERS + LAYER_SI;
1130
}
1131
else{
1132
base = SEC_CHIP_LAYERS + SEC_PACK_LAYERS;
1133
inner_layers = nl - DEFAULT_PACK_LAYERS - SEC_PACK_LAYERS - SEC_CHIP_LAYERS;
1134
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
1135
}
1136
}
1137
else{
1138
base = 0;
1139
inner_layers = nl - DEFAULT_PACK_LAYERS;
1140
silidx = LAYER_SI;
1141
}
1142
1143
if (model->has_lcf)
1144
for(i=base; i < (base+inner_layers); i++){
1145
delete_b2gmap(model->layers[i].b2gmap, model->rows, model->cols);
1146
free(model->layers[i].g2bmap);
1147
free_flp(model->layers[i].flp, FALSE, FALSE);
1148
}
1149
/* only the silicon layer has allocated space for the maps.
1150
* all the rest just point to it. also, its floorplan was
1151
* allocated elsewhere. so, we don't need to deallocate those.
1152
*/
1153
else {
1154
delete_b2gmap(model->layers[silidx].b2gmap, model->rows, model->cols);
1155
free(model->layers[silidx].g2bmap);
1156
}
1157
/*BU_3D: If detailed_3d is used then perform delete the b2gmap
1158
* that was allocated for the package */
1159
if(model->config.detailed_3D_used){
1160
int spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
1161
delete_b2gmap(model->layers[spidx].b2gmap, model->rows, model->cols);
1162
if(model_secondary){
1163
int subidx = LAYER_SUB;
1164
delete_b2gmap(model->layers[subidx].b2gmap, model->rows, model->cols);
1165
}
1166
}//end->BU_3D
1167
1168
/* If microchannels are used, delete their configs */
1169
for(i = 0; i < model->n_layers; i++) {
1170
if(model->layers[i].is_microchannel) {
1171
free_microchannel(model->layers[i].microchannel_config);
1172
}
1173
}
1174
1175
free_grid_model_vector(model->last_steady);
1176
free_grid_model_vector(model->last_trans);
1177
free(model->layers);
1178
free(model);
1179
}
1180
1181
/* differs from 'dvector()' in that memory for internal nodes is also allocated */
1182
double *hotspot_vector_grid(grid_model_t *model)
1183
{
1184
double total_nodes;
1185
if (model->total_n_blocks <= 0)
1186
fatal("total_n_blocks is not greater than zero\n");
1187
1188
if (model->config.model_secondary)
1189
total_nodes = model->total_n_blocks + EXTRA + EXTRA_SEC;
1190
else
1191
total_nodes = model->total_n_blocks + EXTRA;
1192
1193
return dvector(total_nodes);
1194
}
1195
1196
/* copy 'src' to 'dst' except for a window of 'size'
1197
* elements starting at 'at'. useful in floorplan
1198
* compaction. can be used only with default layer
1199
* configuration as all layers should have the same
1200
* floorplan. incompatible with layer configuration
1201
* file.
1202
*/
1203
void trim_hotspot_vector_grid(grid_model_t *model, double *dst, double *src,
1204
int at, int size)
1205
{
1206
int i;
1207
1208
double total_nodes;
1209
if (model->config.model_secondary)
1210
total_nodes = model->total_n_blocks + EXTRA + EXTRA_SEC;
1211
else
1212
total_nodes = model->total_n_blocks + EXTRA;
1213
1214
if (model->has_lcf)
1215
fatal("trim_hotspot_vector_grid called with lcf file\n");
1216
for (i=0; i < at && i < total_nodes; i++)
1217
dst[i] = src[i];
1218
for(i=at+size; i < total_nodes; i++)
1219
dst[i-size] = src[i];
1220
}
1221
1222
/* update the model corresponding to floorplan compaction */
1223
void resize_thermal_model_grid(grid_model_t *model, int n_units)
1224
{
1225
int i;
1226
1227
if (model->has_lcf)
1228
fatal("resize_thermal_model_grid called with lcf file\n");
1229
if (n_units > model->base_n_units)
1230
fatal("resizing grid model to more than the allocated space\n");
1231
1232
/* count the total no. of blocks again */
1233
model->total_n_blocks = 0;
1234
for(i=0; i < model->n_layers; i++)
1235
model->total_n_blocks += model->layers[i].flp->n_units;
1236
1237
/* nothing more needs to be done because the only data structure
1238
* that is dependent on flp->n_units is g2bmap (others are
1239
* dependent on 'grid size' which does not change because
1240
* of resizing). g2bmap is a 1-d array and needs no reallocation
1241
*/
1242
}
1243
1244
/* sets the temperature of a vector 'temp' allocated using 'hotspot_vector' */
1245
void set_temp_grid(grid_model_t *model, double *temp, double val)
1246
{
1247
int i;
1248
1249
double total_nodes;
1250
if (model->config.model_secondary)
1251
total_nodes = model->total_n_blocks + EXTRA + EXTRA_SEC;
1252
else
1253
total_nodes = model->total_n_blocks + EXTRA;
1254
1255
if (model->total_n_blocks <= 0)
1256
fatal("total_n_blocks is not greater than zero\n");
1257
for(i=0; i < total_nodes; i++)
1258
temp[i] = val;
1259
}
1260
1261
/* dump the steady state grid temperatures of the top layer onto 'file' */
1262
void dump_steady_temp_grid (grid_model_t *model, char *file)
1263
{
1264
int i, j, n;
1265
char str[STR_SIZE];
1266
FILE *fp;
1267
1268
if (!model->r_ready)
1269
fatal("R model not ready\n");
1270
1271
if (!strcasecmp(file, "stdout"))
1272
fp = stdout;
1273
else if (!strcasecmp(file, "stderr"))
1274
fp = stderr;
1275
else
1276
fp = fopen (file, "w");
1277
1278
if (!fp) {
1279
sprintf (str,"error: %s could not be opened for writing\n", file);
1280
fatal(str);
1281
}
1282
1283
for(n=0; n < model->n_layers; n++) {
1284
fprintf(fp, "Layer %d:\n", n);
1285
for(i=0; i < model->rows; i++){
1286
for(j=0; j < model->cols; j++){
1287
fprintf(fp, "%d\t%.2f\n", i*model->cols+j,
1288
model->last_steady->cuboid[n][i][j]);
1289
}
1290
}
1291
}
1292
1293
if(fp != stdout && fp != stderr)
1294
fclose(fp);
1295
}
1296
1297
void dump_transient_temp_grid(grid_model_t *model, int trace_num, double sampling_intvl, char *filename) {
1298
FILE *grid_transient_fp = fopen(filename, "a");
1299
1300
if(!grid_transient_fp) {
1301
char err_message[STR_SIZE];
1302
strncpy(err_message, "Unable to open ", STR_SIZE);
1303
strncat(err_message, filename, STR_SIZE - strlen(err_message));
1304
strncat(err_message, " for appending\n", STR_SIZE - strlen(err_message));
1305
fatal(err_message);
1306
}
1307
1308
fprintf(grid_transient_fp, "t = %lf\n", trace_num * sampling_intvl);
1309
for(int l = 0; l < model->n_layers; l++) {
1310
fprintf(grid_transient_fp, "Layer %d:\n", l);
1311
for(int i = 0; i < model->rows; i++) {
1312
for(int j = 0; j < model->cols; j++) {
1313
fprintf(grid_transient_fp, "%d\t%.2f\n", i*model->cols + j, model->last_trans->cuboid[l][i][j]);
1314
}
1315
}
1316
}
1317
1318
fclose(grid_transient_fp);
1319
}
1320
1321
/* dump temperature vector alloced using 'hotspot_vector' to 'file' */
1322
void dump_temp_grid(grid_model_t *model, double *temp, char *file)
1323
{
1324
int i, n, base = 0;
1325
char str[STR_SIZE];
1326
FILE *fp;
1327
1328
int extra_nodes;
1329
int model_secondary = model->config.model_secondary;
1330
int nl = model->n_layers;
1331
int spidx, hsidx, silidx, intidx, c4idx, metalidx, subidx, solderidx, pcbidx;
1332
1333
if (model_secondary)
1334
extra_nodes = EXTRA + EXTRA_SEC;
1335
else
1336
extra_nodes = EXTRA;
1337
1338
if (!strcasecmp(file, "stdout"))
1339
fp = stdout;
1340
else if (!strcasecmp(file, "stderr"))
1341
fp = stderr;
1342
else
1343
fp = fopen (file, "w");
1344
1345
if (!fp) {
1346
sprintf (str,"error: %s could not be opened for writing\n", file);
1347
fatal(str);
1348
}
1349
1350
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
1351
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
1352
if (model_secondary) {
1353
subidx = LAYER_SUB;
1354
solderidx = LAYER_SOLDER;
1355
pcbidx = LAYER_PCB;
1356
if(!model->has_lcf){
1357
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
1358
intidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_INT;
1359
c4idx = SEC_PACK_LAYERS + LAYER_C4;
1360
metalidx = SEC_PACK_LAYERS + LAYER_METAL;
1361
}
1362
}
1363
else{
1364
silidx = LAYER_SI;
1365
intidx = LAYER_INT;
1366
}
1367
1368
/* layer temperatures */
1369
for(n=0; n < model->n_layers; n++) {
1370
if (!model_secondary) {
1371
/* default set of layers */
1372
if (!model->has_lcf) {
1373
if(n == silidx)
1374
strcpy(str,"");
1375
else if(n == intidx)
1376
strcpy(str,"iface_");
1377
else if(n == spidx)
1378
strcpy(str,"hsp_");
1379
else if(n == hsidx)
1380
strcpy(str,"hsink_");
1381
else
1382
fatal("unknown layer\n");
1383
} else {
1384
if (n == spidx)
1385
strcpy(str, "hsp_"); /* spreader layer */
1386
else if (n == hsidx)
1387
strcpy(str, "hsink_"); /* heatsink layer */
1388
else /* other layers */
1389
sprintf(str,"layer_%d_", n);
1390
}
1391
} else {
1392
/* default set of layers */
1393
if (!model->has_lcf) {
1394
if(n == silidx)
1395
strcpy(str,"");
1396
else if(n == intidx)
1397
strcpy(str,"iface_");
1398
else if(n == spidx)
1399
strcpy(str,"hsp_");
1400
else if(n == hsidx)
1401
strcpy(str,"hsink_");
1402
else if(n == metalidx)
1403
strcpy(str,"metal_");
1404
else if(n == c4idx)
1405
strcpy(str,"c4_");
1406
else if(n == subidx)
1407
strcpy(str,"sub_");
1408
else if(n == solderidx)
1409
strcpy(str,"solder_");
1410
else if(n == pcbidx)
1411
strcpy(str,"pcb_");
1412
else
1413
fatal("unknown layer\n");
1414
/* layer configuration file */
1415
} else {
1416
if (n == spidx)
1417
strcpy(str, "hsp_"); /* spreader layer */
1418
else if (n == hsidx)
1419
strcpy(str, "hsink_"); /* heatsink layer */
1420
else if (n == subidx)
1421
strcpy(str, "sub_"); /* package substrate layer */
1422
else if (n == solderidx)
1423
strcpy(str, "solder_"); /* solder layer */
1424
else if (n == pcbidx)
1425
strcpy(str, "pcb_"); /* pcb layer */
1426
else /* other layers */
1427
sprintf(str,"layer_%d_", n);
1428
}
1429
}
1430
1431
for(i=0; i < model->layers[n].flp->n_units; i++)
1432
fprintf(fp, "%s%s\t%.2f\n", str,
1433
model->layers[n].flp->units[i].name, temp[base+i]);
1434
base += model->layers[n].flp->n_units;
1435
}
1436
1437
if (base != model->total_n_blocks)
1438
fatal("total_n_blocks failed to tally\n");
1439
1440
/* internal node temperatures */
1441
for (i=0; i < extra_nodes; i++) {
1442
sprintf(str, "inode_%d", i);
1443
fprintf(fp, "%s\t%.2f\n", str, temp[base+i]);
1444
}
1445
if(fp != stdout && fp != stderr)
1446
fclose(fp);
1447
}
1448
1449
void copy_temp_grid(grid_model_t *model, double *dst, double *src)
1450
{
1451
if (!model->config.model_secondary)
1452
copy_dvector(dst, src, model->total_n_blocks + EXTRA);
1453
else
1454
copy_dvector(dst, src, model->total_n_blocks + EXTRA + EXTRA_SEC);
1455
}
1456
1457
/*
1458
* read temperature vector alloced using 'hotspot_vector' from 'file'
1459
* which was dumped using 'dump_temp'. values are clipped to thermal
1460
* threshold based on 'clip'
1461
*/
1462
void read_temp_grid(grid_model_t *model, double *temp, char *file, int clip)
1463
{
1464
int i, n, idx, base = 0;
1465
double max=0, val;
1466
char *ptr, str1[LINE_SIZE], str2[LINE_SIZE];
1467
char name[STR_SIZE], format[STR_SIZE];
1468
FILE *fp;
1469
1470
int model_secondary = model->config.model_secondary;
1471
int extra_nodes;
1472
int nl = model->n_layers;
1473
int spidx, hsidx, silidx, intidx, c4idx, metalidx, subidx, solderidx, pcbidx;
1474
1475
if (model->config.model_secondary)
1476
extra_nodes = EXTRA + EXTRA_SEC;
1477
else
1478
extra_nodes = EXTRA;
1479
1480
if (!strcasecmp(file, "stdin"))
1481
fp = stdin;
1482
else
1483
fp = fopen (file, "r");
1484
1485
if (!fp) {
1486
sprintf (str1,"error: %s could not be opened for reading\n", file);
1487
fatal(str1);
1488
}
1489
1490
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
1491
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
1492
if (model_secondary) {
1493
subidx = LAYER_SUB;
1494
solderidx = LAYER_SOLDER;
1495
pcbidx = LAYER_PCB;
1496
if(!model->has_lcf){
1497
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_SI;
1498
intidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS + LAYER_INT;
1499
c4idx = SEC_PACK_LAYERS + LAYER_C4;
1500
metalidx = SEC_PACK_LAYERS + LAYER_METAL;
1501
}
1502
}
1503
else{
1504
silidx = LAYER_SI;
1505
intidx = LAYER_INT;
1506
}
1507
1508
/* temperatures of the different layers */
1509
for (n=0; n < model->n_layers; n++) {
1510
if (!model_secondary) {
1511
/* default set of layers */
1512
if (!model->has_lcf) {
1513
if(n == silidx)
1514
strcpy(format,"%s%lf");
1515
else if(n == intidx)
1516
strcpy(format,"iface_%s%lf");
1517
else if(n == spidx)
1518
strcpy(format,"hsp_%s%lf");
1519
else if(n == hsidx)
1520
strcpy(format,"hsink_%s%lf");
1521
else
1522
fatal("unknown layer\n");
1523
} else {
1524
/* layer configuration file */
1525
if (n == spidx)
1526
strcpy(format, "hsp_%s%lf"); /* spreader layer */
1527
else if (n == hsidx)
1528
strcpy(format, "hsink_%s%lf"); /* heatsink layer */
1529
else /* other layers */
1530
sprintf(format,"layer_%d_%%s%%lf", n);
1531
}
1532
} else {
1533
/* default set of layers */
1534
if (!model->has_lcf) {
1535
if(n == silidx)
1536
strcpy(format,"%s%lf");
1537
else if(n == intidx)
1538
strcpy(format,"iface_%s%lf");
1539
else if(n == spidx)
1540
strcpy(format,"hsp_%s%lf");
1541
else if(n == hsidx)
1542
strcpy(format,"hsink_%s%lf");
1543
else if(n == metalidx)
1544
strcpy(format,"metal_%s%lf");
1545
else if(n == c4idx)
1546
strcpy(format,"c4_%s%lf");
1547
else if(n == subidx)
1548
strcpy(format,"sub_%s%lf");
1549
else if(n == solderidx)
1550
strcpy(format,"solder_%s%lf");
1551
else if(n == pcbidx)
1552
strcpy(format,"pcb_%s%lf");
1553
else
1554
fatal("unknown layer\n");
1555
/* layer configuration file */
1556
} else {
1557
if (n == spidx)
1558
strcpy(format, "hsp_%s%lf"); /* spreader layer */
1559
else if (n == hsidx)
1560
strcpy(format, "hsink_%s%lf"); /* heatsink layer */
1561
else if (n == subidx)
1562
strcpy(format, "sub_%s%lf"); /* package substrate layer */
1563
else if (n == solderidx)
1564
strcpy(format, "solder_%s%lf"); /* solder ball layer */
1565
else if (n == pcbidx)
1566
strcpy(format, "pcb_%s%lf"); /* PCB layer */
1567
else /* other layers */
1568
sprintf(format,"layer_%d_%%s%%lf", n);
1569
}
1570
}
1571
1572
for (i=0; i < model->layers[n].flp->n_units; i++) {
1573
fgets(str1, LINE_SIZE, fp);
1574
if (feof(fp))
1575
fatal("not enough lines in temperature file\n");
1576
strcpy(str2, str1);
1577
/* ignore comments and empty lines */
1578
ptr = strtok(str1, " \r\t\n");
1579
if (!ptr || ptr[0] == '#') {
1580
i--;
1581
continue;
1582
}
1583
if (sscanf(str2, format, name, &val) != 2)
1584
fatal("invalid temperature file format\n");
1585
idx = get_blk_index(model->layers[n].flp, name);
1586
if (idx >= 0)
1587
temp[base+idx] = val;
1588
else /* since get_blk_index calls fatal, the line below cannot be reached */
1589
fatal ("unit in temperature file not found in floorplan\n");
1590
1591
/* find max temp on the top layer
1592
* (silicon for the default set of layers)
1593
*/
1594
if (n == 0 && temp[idx] > max)
1595
max = temp[idx];
1596
}
1597
base += model->layers[n].flp->n_units;
1598
}
1599
1600
if (base != model->total_n_blocks)
1601
fatal("total_n_blocks failed to tally\n");
1602
1603
/* internal node temperatures */
1604
for (i=0; i < extra_nodes; i++) {
1605
fgets(str1, LINE_SIZE, fp);
1606
if (feof(fp))
1607
fatal("not enough lines in temperature file\n");
1608
strcpy(str2, str1);
1609
/* ignore comments and empty lines */
1610
ptr = strtok(str1, " \r\t\n");
1611
if (!ptr || ptr[0] == '#') {
1612
i--;
1613
continue;
1614
}
1615
if (sscanf(str2, "%s%lf", name, &val) != 2)
1616
fatal("invalid temperature file format\n");
1617
sprintf(str1, "inode_%d", i);
1618
if (strcasecmp(str1, name))
1619
fatal("invalid temperature file format\n");
1620
temp[base+i] = val;
1621
}
1622
1623
fgets(str1, LINE_SIZE, fp);
1624
if (!feof(fp))
1625
fatal("too many lines in temperature file\n");
1626
1627
if(fp != stdin)
1628
fclose(fp);
1629
1630
/* clipping */
1631
if (clip && (max > model->config.thermal_threshold)) {
1632
/* if max has to be brought down to thermal_threshold,
1633
* (w.r.t the ambient) what is the scale down factor?
1634
*/
1635
double factor = (model->config.thermal_threshold - model->config.ambient) /
1636
(max - model->config.ambient);
1637
1638
/* scale down all temperature differences (from ambient) by the same factor */
1639
for (i=0; i < model->total_n_blocks + extra_nodes; i++)
1640
temp[i] = (temp[i]-model->config.ambient)*factor + model->config.ambient;
1641
}
1642
}
1643
1644
/* dump power numbers to file */
1645
void dump_power_grid(grid_model_t *model, double *power, char *file)
1646
{
1647
int i, n, base = 0;
1648
char str[STR_SIZE];
1649
FILE *fp;
1650
1651
if (!strcasecmp(file, "stdout"))
1652
fp = stdout;
1653
else if (!strcasecmp(file, "stderr"))
1654
fp = stderr;
1655
else
1656
fp = fopen (file, "w");
1657
if (!fp) {
1658
sprintf (str,"error: %s could not be opened for writing\n", file);
1659
fatal(str);
1660
}
1661
1662
/* dump values only for the layers dissipating power */
1663
for(n=0; n < model->n_layers; n++) {
1664
if (model->layers[n].has_power) {
1665
for(i=0; i < model->layers[n].flp->n_units; i++)
1666
if (model->has_lcf)
1667
fprintf(fp, "layer_%d_%s\t%.6f\n", n,
1668
model->layers[n].flp->units[i].name, power[base+i]);
1669
else
1670
fprintf(fp, "%s\t%.6f\n",
1671
model->layers[n].flp->units[i].name, power[base+i]);
1672
}
1673
base += model->layers[n].flp->n_units;
1674
}
1675
1676
if(fp != stdout && fp != stderr)
1677
fclose(fp);
1678
}
1679
1680
/*
1681
* read power vector alloced using 'hotspot_vector' from 'file'
1682
* which was dumped using 'dump_power'.
1683
*/
1684
void read_power_grid(grid_model_t *model, double *power, char *file)
1685
{
1686
int i, idx, n, base = 0;
1687
double val;
1688
char *ptr, str1[LINE_SIZE], str2[LINE_SIZE];
1689
char name[STR_SIZE], format[STR_SIZE];
1690
FILE *fp;
1691
1692
if (!strcasecmp(file, "stdin"))
1693
fp = stdin;
1694
else
1695
fp = fopen (file, "r");
1696
if (!fp) {
1697
sprintf (str1,"error: %s could not be opened for reading\n", file);
1698
fatal(str1);
1699
}
1700
1701
/* lcf file could potentially specify more than one power dissipating
1702
* layer. hence, units with zero power within a layer cannot be left
1703
* out in the power file.
1704
*/
1705
if (model->has_lcf) {
1706
for(n=0; n < model->n_layers; n++) {
1707
if (model->layers[n].has_power)
1708
for(i=0; i < model->layers[n].flp->n_units; i++) {
1709
fgets(str1, LINE_SIZE, fp);
1710
if (feof(fp))
1711
fatal("not enough lines in power file\n");
1712
strcpy(str2, str1);
1713
1714
/* ignore comments and empty lines */
1715
ptr = strtok(str1, " \r\t\n");
1716
if (!ptr || ptr[0] == '#') {
1717
i--;
1718
continue;
1719
}
1720
1721
sprintf(format, "layer_%d_%%s%%lf", n);
1722
if (sscanf(str2, format, name, &val) != 2)
1723
fatal("invalid power file format\n");
1724
idx = get_blk_index(model->layers[n].flp, name);
1725
if (idx >= 0)
1726
power[base+idx] = val;
1727
/* since get_blk_index calls fatal, the line below cannot be reached */
1728
else
1729
fatal ("unit in power file not found in floorplan\n");
1730
}
1731
base += model->layers[n].flp->n_units;
1732
}
1733
fgets(str1, LINE_SIZE, fp);
1734
if (!feof(fp))
1735
fatal("too many lines in power file\n");
1736
/* default layer configuration. so only one layer
1737
* has power dissipation. units with zero power
1738
* can be omitted in the power file
1739
*/
1740
} else {
1741
while(!feof(fp)) {
1742
fgets(str1, LINE_SIZE, fp);
1743
if (feof(fp))
1744
break;
1745
strcpy(str2, str1);
1746
1747
/* ignore comments and empty lines */
1748
ptr = strtok(str1, " \r\t\n");
1749
if (!ptr || ptr[0] == '#')
1750
continue;
1751
1752
if (sscanf(str2, "%s%lf", name, &val) != 2)
1753
fatal("invalid power file format\n");
1754
idx = get_blk_index(model->layers[LAYER_SI].flp, name);
1755
if (idx >= 0)
1756
power[idx] = val;
1757
else /* since get_blk_index calls fatal, the line below cannot be reached */
1758
fatal ("unit in power file not found in floorplan\n");
1759
}
1760
}
1761
1762
if(fp != stdin)
1763
fclose(fp);
1764
}
1765
1766
double find_max_temp_grid(grid_model_t *model, double *temp)
1767
{
1768
int i;
1769
double max = 0.0;
1770
int silidx;
1771
1772
if (!model->config.model_secondary) {
1773
silidx = LAYER_SI;
1774
} else {
1775
if(model->has_lcf)
1776
silidx = SEC_PACK_LAYERS;
1777
else
1778
silidx = SEC_PACK_LAYERS + SEC_CHIP_LAYERS;
1779
}
1780
1781
/* max temperature occurs on the top-most layer */
1782
for(i=0; i < model->layers[silidx].flp->n_units; i++) {
1783
if (temp[i] < 0)
1784
fatal("negative temperature!\n");
1785
else if (max < temp[i])
1786
max = temp[i];
1787
}
1788
1789
return max;
1790
}
1791
1792
double find_avg_temp_grid(grid_model_t *model, double *temp)
1793
{
1794
int i, n, base = 0, count = 0;
1795
double sum = 0.0;
1796
/* average temperature of all the power dissipating blocks */
1797
for(n=0; n < model->n_layers; n++) {
1798
if (model->layers[n].has_power) {
1799
for(i=0; i < model->layers[n].flp->n_units; i++) {
1800
if (temp[base+i] < 0)
1801
fatal("negative temperature!\n");
1802
else
1803
sum += temp[base+i];
1804
}
1805
count += model->layers[n].flp->n_units;
1806
}
1807
base += model->layers[n].flp->n_units;
1808
}
1809
1810
if (!count)
1811
fatal("no power dissipating units?!\n");
1812
return (sum / count);
1813
}
1814
1815
/* calculate average heatsink temperature for natural convection package */
1816
double calc_sink_temp_grid(grid_model_t *model, double *temp, thermal_config_t *config)
1817
{
1818
int i, n, base = 0;
1819
int hsidx = model->n_layers - DEFAULT_PACK_LAYERS + LAYER_SINK;
1820
double sum = 0.0;
1821
double spr_size = config->s_spreader*config->s_spreader;
1822
double sink_size = config->s_sink*config->s_sink;
1823
1824
/* heat sink core */
1825
for(n=0; n < hsidx; n++)
1826
base += model->layers[n].flp->n_units;
1827
1828
for(i=base; i < base+model->layers[n].flp->n_units; i++)
1829
if (temp[i] < 0)
1830
fatal("negative temperature!\n");
1831
else /* area-weighted average */
1832
sum += temp[i]*(model->layers[n].flp->units[i-base].width*model->layers[n].flp->units[i-base].height);
1833
1834
/* heat sink periphery */
1835
base = model->total_n_blocks;
1836
1837
for(i=SINK_C_W; i <= SINK_C_E; i++)
1838
if (temp[i+base] < 0)
1839
fatal("negative temperature!\n");
1840
else
1841
sum += temp[i+base]*0.25*(config->s_spreader+model->height)*(config->s_spreader-model->width);
1842
1843
for(i=SINK_C_N; i <= SINK_C_S; i++)
1844
if (temp[i+base] < 0)
1845
fatal("negative temperature!\n");
1846
else
1847
sum += temp[i+base]*0.25*(config->s_spreader+model->width)*(config->s_spreader-model->height);
1848
1849
for(i=SINK_W; i <= SINK_S; i++)
1850
if (temp[i+base] < 0)
1851
fatal("negative temperature!\n");
1852
else
1853
sum += temp[i+base]*0.25*(sink_size-spr_size);
1854
1855
return (sum / sink_size);
1856
}
1857
1858
/* grid_model_vector routines */
1859
1860
/* constructor */
1861
grid_model_vector_t *new_grid_model_vector(grid_model_t *model)
1862
{
1863
grid_model_vector_t *v;
1864
1865
int extra_nodes;
1866
if (model->config.model_secondary)
1867
extra_nodes = EXTRA + EXTRA_SEC;
1868
else
1869
extra_nodes = EXTRA;
1870
1871
v = (grid_model_vector_t *) calloc (1, sizeof(grid_model_vector_t));
1872
if (!v)
1873
fatal("memory allocation error\n");
1874
1875
v->cuboid = dcuboid_tail(model->rows, model->cols, model->n_layers, extra_nodes);
1876
v->extra = v->cuboid[0][0] + model->rows * model->cols * model->n_layers;
1877
return v;
1878
}
1879
1880
/* destructor */
1881
void free_grid_model_vector(grid_model_vector_t *v)
1882
{
1883
free_dcuboid(v->cuboid);
1884
free(v);
1885
}
1886
1887
/* translate power/temperature between block and grid vectors */
1888
void xlate_vector_b2g(grid_model_t *model, double *b, grid_model_vector_t *g, int type)
1889
{
1890
int i, j, n, base = 0;
1891
double area;
1892
1893
int extra_nodes;
1894
if (model->config.model_secondary)
1895
extra_nodes = EXTRA + EXTRA_SEC;
1896
else
1897
extra_nodes = EXTRA;
1898
1899
/* area of a single grid cell */
1900
area = (model->width * model->height) / (model->cols * model->rows);
1901
1902
for(n=0; n < model->n_layers; n++) {
1903
for(i=0; i < model->rows; i++)
1904
for(j=0; j < model->cols; j++) {
1905
/* for each grid cell, the power density / temperature are
1906
* the average of the power densities / temperatures of the
1907
* blocks in it weighted by their occupancies
1908
*/
1909
/* convert power density to power */
1910
if (type == V_POWER)
1911
g->cuboid[n][i][j] = blist_avg(model->layers[n].b2gmap[i][j],
1912
model->layers[n].flp, &b[base], type) * area;
1913
/* no conversion necessary for temperature */
1914
else if (type == V_TEMP)
1915
g->cuboid[n][i][j] = blist_avg(model->layers[n].b2gmap[i][j],
1916
model->layers[n].flp, &b[base], type);
1917
else
1918
fatal("unknown vector type\n");
1919
}
1920
/* keep track of the beginning address of this layer in the
1921
* block power vector
1922
*/
1923
base += model->layers[n].flp->n_units;
1924
}
1925
1926
/* extra spreader and sink nodes */
1927
for(i=0; i < extra_nodes; i++)
1928
g->extra[i] = b[base+i];
1929
}
1930
1931
/* translate temperature between grid and block vectors */
1932
void xlate_temp_g2b(grid_model_t *model, double *b, grid_model_vector_t *g)
1933
{
1934
int i, j, n, u, base = 0, count;
1935
int i1, j1, i2, j2, ci1, cj1, ci2, cj2;
1936
double min, max, avg;
1937
1938
int extra_nodes;
1939
if (model->config.model_secondary)
1940
extra_nodes = EXTRA + EXTRA_SEC;
1941
else
1942
extra_nodes = EXTRA;
1943
1944
for(n=0; n < model->n_layers; n++) {
1945
for(u=0; u < model->layers[n].flp->n_units; u++) {
1946
/* extent of this unit in grid cell units */
1947
i1 = model->layers[n].g2bmap[u].i1;
1948
j1 = model->layers[n].g2bmap[u].j1;
1949
i2 = model->layers[n].g2bmap[u].i2;
1950
j2 = model->layers[n].g2bmap[u].j2;
1951
1952
/* map the center grid cell's temperature to the block */
1953
if (model->map_mode == GRID_CENTER) {
1954
/* center co-ordinates */
1955
ci1 = (i1 + i2) / 2;
1956
cj1 = (j1 + j2) / 2;
1957
/* in case of even no. of cells, center
1958
* is the average of two central cells
1959
*/
1960
/* ci2 = ci1-1 when even, ci1 otherwise */
1961
ci2 = ci1 - !((i2-i1) % 2);
1962
/* cj2 = cj1-1 when even, cj1 otherwise */
1963
cj2 = cj1 - !((j2-j1) % 2);
1964
1965
b[base+u] = (g->cuboid[n][ci1][cj1] + g->cuboid[n][ci2][cj1] +
1966
g->cuboid[n][ci1][cj2] + g->cuboid[n][ci2][cj2]) / 4;
1967
continue;
1968
}
1969
1970
/* find the min/max/avg temperatures of the
1971
* grid cells in this block
1972
*/
1973
avg = 0.0;
1974
count = 0;
1975
min = max = g->cuboid[n][i1][j1];
1976
for(i=i1; i < i2; i++)
1977
for(j=j1; j < j2; j++) {
1978
avg += g->cuboid[n][i][j];
1979
if (g->cuboid[n][i][j] < min)
1980
min = g->cuboid[n][i][j];
1981
if (g->cuboid[n][i][j] > max)
1982
max = g->cuboid[n][i][j];
1983
count++;
1984
}
1985
1986
/* map to output accordingly */
1987
switch (model->map_mode)
1988
{
1989
case GRID_AVG:
1990
b[base+u] = avg / count;
1991
break;
1992
case GRID_MIN:
1993
b[base+u] = min;
1994
break;
1995
case GRID_MAX:
1996
b[base+u] = max;
1997
break;
1998
/* taken care of already */
1999
case GRID_CENTER:
2000
break;
2001
default:
2002
fatal("unknown mapping mode\n");
2003
break;
2004
}
2005
}
2006
/* keep track of the beginning address of this layer in the
2007
* block power vector
2008
*/
2009
base += model->layers[n].flp->n_units;
2010
}
2011
2012
/* extra spreader and sink nodes */
2013
for(i=0; i < extra_nodes; i++)
2014
b[base+i] = g->extra[i];
2015
}
2016
2017
/* setting package nodes' power numbers */
2018
void set_internal_power_grid(grid_model_t *model, double *power)
2019
{
2020
if (!model->config.model_secondary)
2021
zero_dvector(&power[model->total_n_blocks], EXTRA);
2022
else
2023
zero_dvector(&power[model->total_n_blocks], EXTRA+EXTRA_SEC);
2024
}
2025
2026
/* set up initial temperatures for the steady state solution
2027
* heuristically (ignoring the lateral resistances)
2028
*/
2029
void set_heuristic_temp(grid_model_t *model, grid_model_vector_t *power,
2030
grid_model_vector_t *temp)
2031
{
2032
int n, i, j, nl, nr, nc;
2033
double **sum;
2034
2035
/* shortcuts */
2036
nl = model->n_layers;
2037
nr = model->rows;
2038
nc = model->cols;
2039
2040
/* package temperatures */
2041
/* if all lateral resistances are considered infinity, all peripheral
2042
* package nodes are at the ambient temperature
2043
*/
2044
temp->extra[SINK_N] = temp->extra[SINK_S] =
2045
temp->extra[SINK_E] = temp->extra[SINK_W] =
2046
temp->extra[SINK_C_N] = temp->extra[SINK_C_S] =
2047
temp->extra[SINK_C_E] = temp->extra[SINK_C_W] =
2048
temp->extra[SP_N] = temp->extra[SP_S] =
2049
temp->extra[SP_E] = temp->extra[SP_W] =
2050
model->config.ambient;
2051
2052
if (model->config.model_secondary) {
2053
temp->extra[PCB_N] = temp->extra[PCB_S] =
2054
temp->extra[PCB_E] = temp->extra[PCB_W] =
2055
temp->extra[PCB_C_N] = temp->extra[PCB_C_S] =
2056
temp->extra[PCB_C_E] = temp->extra[PCB_C_W] =
2057
temp->extra[SOLDER_N] = temp->extra[SOLDER_S] =
2058
temp->extra[SOLDER_E] = temp->extra[SOLDER_W] =
2059
temp->extra[SUB_N] = temp->extra[SUB_S] =
2060
temp->extra[SUB_E] = temp->extra[SUB_W] =
2061
model->config.ambient;
2062
}
2063
2064
/* layer temperatures */
2065
/* add up power for each grid cell across all layers */
2066
sum = dmatrix(nr, nc);
2067
for(n=0; n < nl; n++)
2068
scaleadd_dvector(sum[0], sum[0], power->cuboid[n][0], nr*nc, 1.0);
2069
2070
/* last layer */
2071
for(i=0; i < nr; i++)
2072
for(j=0; j < nc; j++)
2073
temp->cuboid[nl-1][i][j] = model->config.ambient + sum[i][j] *
2074
model->layers[nl-1].rz;
2075
/* subtract away the layer's power */
2076
scaleadd_dvector(sum[0], sum[0], power->cuboid[nl-1][0], nr*nc, -1.0);
2077
2078
/* go from last-1 to first */
2079
for(n=nl-2; n >= 0; n--) {
2080
/* nth layer temp is n+1th temp + cumul_power * rz of the nth layer */
2081
scaleadd_dvector(temp->cuboid[n][0], temp->cuboid[n+1][0], sum[0],
2082
nr*nc, model->layers[n].rz);
2083
/* subtract away the layer's power */
2084
scaleadd_dvector(sum[0], sum[0], power->cuboid[n][0], nr*nc, -1.0);
2085
}
2086
free_dmatrix(sum);
2087
}
2088
2089
/* single steady state iteration of grid solver - package part */
2090
double single_iteration_steady_pack(grid_model_t *model, grid_model_vector_t *power,
2091
grid_model_vector_t *temp)
2092
{
2093
int i, j;
2094
2095
double delta[EXTRA+EXTRA_SEC], max = 0;
2096
/* sum of the conductances */
2097
double csum;
2098
/* weighted sum of temperatures */
2099
double wsum;
2100
2101
/* shortcuts */
2102
double *v = temp->extra;
2103
package_RC_t *pk = &model->pack;
2104
thermal_config_t *c = &model->config;
2105
layer_t *l = model->layers;
2106
int nl = model->n_layers;
2107
int nr = model->rows;
2108
int nc = model->cols;
2109
int spidx, hsidx, subidx, solderidx, pcbidx;
2110
int model_secondary = model->config.model_secondary;
2111
2112
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
2113
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
2114
if (model_secondary) {
2115
subidx = LAYER_SUB;
2116
solderidx = LAYER_SOLDER;
2117
pcbidx = LAYER_PCB;
2118
}
2119
2120
/* sink outer north/south */
2121
csum = 1.0/(pk->r_hs_per + pk->r_amb_per) + 1.0/(pk->r_hs2_y + pk->r_hs);
2122
wsum = c->ambient/(pk->r_hs_per + pk->r_amb_per) + v[SINK_C_N]/(pk->r_hs2_y + pk->r_hs);
2123
delta[SINK_N] = fabs(v[SINK_N] - wsum / csum);
2124
v[SINK_N] = wsum / csum;
2125
wsum = c->ambient/(pk->r_hs_per + pk->r_amb_per) + v[SINK_C_S]/(pk->r_hs2_y + pk->r_hs);
2126
delta[SINK_S] = fabs(v[SINK_S] - wsum / csum);
2127
v[SINK_S] = wsum / csum;
2128
2129
/* sink outer west/east */
2130
csum = 1.0/(pk->r_hs_per + pk->r_amb_per) + 1.0/(pk->r_hs2_x + pk->r_hs);
2131
wsum = c->ambient/(pk->r_hs_per + pk->r_amb_per) + v[SINK_C_W]/(pk->r_hs2_x + pk->r_hs);
2132
delta[SINK_W] = fabs(v[SINK_W] - wsum / csum);
2133
v[SINK_W] = wsum / csum;
2134
wsum = c->ambient/(pk->r_hs_per + pk->r_amb_per) + v[SINK_C_E]/(pk->r_hs2_x + pk->r_hs);
2135
delta[SINK_E] = fabs(v[SINK_E] - wsum / csum);
2136
v[SINK_E] = wsum / csum;
2137
2138
/* sink inner north/south */
2139
/* partition r_hs1_y among all the nc grid cells. edge cell has half the ry */
2140
csum = nc / (l[hsidx].ry / 2.0 + nc * pk->r_hs1_y);
2141
csum += 1.0/(pk->r_hs_c_per_y + pk->r_amb_c_per_y) +
2142
1.0/pk->r_sp_per_y + 1.0/(pk->r_hs2_y + pk->r_hs);
2143
2144
wsum = 0.0;
2145
for(j=0; j < nc; j++)
2146
wsum += temp->cuboid[hsidx][0][j];
2147
wsum /= (l[hsidx].ry / 2.0 + nc * pk->r_hs1_y);
2148
wsum += c->ambient/(pk->r_hs_c_per_y + pk->r_amb_c_per_y) +
2149
v[SP_N]/pk->r_sp_per_y + v[SINK_N]/(pk->r_hs2_y + pk->r_hs);
2150
delta[SINK_C_N] = fabs(v[SINK_C_N] - wsum / csum);
2151
v[SINK_C_N] = wsum / csum;
2152
2153
wsum = 0.0;
2154
for(j=0; j < nc; j++)
2155
wsum += temp->cuboid[hsidx][nr-1][j];
2156
wsum /= (l[hsidx].ry / 2.0 + nc * pk->r_hs1_y);
2157
wsum += c->ambient/(pk->r_hs_c_per_y + pk->r_amb_c_per_y) +
2158
v[SP_S]/pk->r_sp_per_y + v[SINK_S]/(pk->r_hs2_y + pk->r_hs);
2159
delta[SINK_C_S] = fabs(v[SINK_C_S] - wsum / csum);
2160
v[SINK_C_S] = wsum / csum;
2161
2162
/* sink inner west/east */
2163
/* partition r_hs1_x among all the nr grid cells. edge cell has half the rx */
2164
csum = nr / (l[hsidx].rx / 2.0 + nr * pk->r_hs1_x);
2165
csum += 1.0/(pk->r_hs_c_per_x + pk->r_amb_c_per_x) +
2166
1.0/pk->r_sp_per_x + 1.0/(pk->r_hs2_x + pk->r_hs);
2167
2168
wsum = 0.0;
2169
for(i=0; i < nr; i++)
2170
wsum += temp->cuboid[hsidx][i][0];
2171
wsum /= (l[hsidx].rx / 2.0 + nr * pk->r_hs1_x);
2172
wsum += c->ambient/(pk->r_hs_c_per_x + pk->r_amb_c_per_x) +
2173
v[SP_W]/pk->r_sp_per_x + v[SINK_W]/(pk->r_hs2_x + pk->r_hs);
2174
delta[SINK_C_W] = fabs(v[SINK_C_W] - wsum / csum);
2175
v[SINK_C_W] = wsum / csum;
2176
2177
wsum = 0.0;
2178
for(i=0; i < nr; i++)
2179
wsum += temp->cuboid[hsidx][i][nc-1];
2180
wsum /= (l[hsidx].rx / 2.0 + nr * pk->r_hs1_x);
2181
wsum += c->ambient/(pk->r_hs_c_per_x + pk->r_amb_c_per_x) +
2182
v[SP_E]/pk->r_sp_per_x + v[SINK_E]/(pk->r_hs2_x + pk->r_hs);
2183
delta[SINK_C_E] = fabs(v[SINK_C_E] - wsum / csum);
2184
v[SINK_C_E] = wsum / csum;
2185
2186
/* spreader north/south */
2187
/* partition r_sp1_y among all the nc grid cells. edge cell has half the ry */
2188
csum = nc / (l[spidx].ry / 2.0 + nc * pk->r_sp1_y);
2189
csum += 1.0/pk->r_sp_per_y;
2190
2191
wsum = 0.0;
2192
for(j=0; j < nc; j++)
2193
wsum += temp->cuboid[spidx][0][j];
2194
wsum /= (l[spidx].ry / 2.0 + nc * pk->r_sp1_y);
2195
wsum += v[SINK_C_N]/pk->r_sp_per_y;
2196
delta[SP_N] = fabs(v[SP_N] - wsum / csum);
2197
v[SP_N] = wsum / csum;
2198
2199
wsum = 0.0;
2200
for(j=0; j < nc; j++)
2201
wsum += temp->cuboid[spidx][nr-1][j];
2202
wsum /= (l[spidx].ry / 2.0 + nc * pk->r_sp1_y);
2203
wsum += v[SINK_C_S]/pk->r_sp_per_y;
2204
delta[SP_S] = fabs(v[SP_S] - wsum / csum);
2205
v[SP_S] = wsum / csum;
2206
2207
/* spreader west/east */
2208
/* partition r_sp1_x among all the nr grid cells. edge cell has half the rx */
2209
csum = nr / (l[spidx].rx / 2.0 + nr * pk->r_sp1_x);
2210
csum += 1.0/pk->r_sp_per_x;
2211
2212
wsum = 0.0;
2213
for(i=0; i < nr; i++)
2214
wsum += temp->cuboid[spidx][i][0];
2215
wsum /= (l[spidx].rx / 2.0 + nr * pk->r_sp1_x);
2216
wsum += v[SINK_C_W]/pk->r_sp_per_x;
2217
delta[SP_W] = fabs(v[SP_W] - wsum / csum);
2218
v[SP_W] = wsum / csum;
2219
2220
wsum = 0.0;
2221
for(i=0; i < nr; i++)
2222
wsum += temp->cuboid[spidx][i][nc-1];
2223
wsum /= (l[spidx].rx / 2.0 + nr * pk->r_sp1_x);
2224
wsum += v[SINK_C_E]/pk->r_sp_per_x;
2225
delta[SP_E] = fabs(v[SP_E] - wsum / csum);
2226
v[SP_E] = wsum / csum;
2227
2228
if (model->config.model_secondary) {
2229
/* secondary path package nodes */
2230
/* PCB outer north/south */
2231
csum = 1.0/(pk->r_amb_sec_per) + 1.0/(pk->r_pcb2_y + pk->r_pcb);
2232
wsum = c->ambient/(pk->r_amb_sec_per) + v[PCB_C_N]/(pk->r_pcb2_y + pk->r_pcb);
2233
delta[PCB_N] = fabs(v[PCB_N] - wsum / csum);
2234
v[PCB_N] = wsum / csum;
2235
wsum = c->ambient/(pk->r_amb_sec_per) + v[PCB_C_S]/(pk->r_pcb2_y + pk->r_pcb);
2236
delta[PCB_S] = fabs(v[PCB_S] - wsum / csum);
2237
v[PCB_S] = wsum / csum;
2238
2239
/* PCB outer west/east */
2240
csum = 1.0/(pk->r_amb_sec_per) + 1.0/(pk->r_pcb2_x + pk->r_pcb);
2241
wsum = c->ambient/(pk->r_amb_sec_per) + v[PCB_C_W]/(pk->r_pcb2_x + pk->r_pcb);
2242
delta[PCB_W] = fabs(v[PCB_W] - wsum / csum);
2243
v[PCB_W] = wsum / csum;
2244
wsum = c->ambient/(pk->r_amb_sec_per) + v[PCB_C_E]/(pk->r_pcb2_x + pk->r_pcb);
2245
delta[PCB_E] = fabs(v[PCB_E] - wsum / csum);
2246
v[PCB_E] = wsum / csum;
2247
2248
/* PCB inner north/south */
2249
/* partition r_pcb1_y among all the nc grid cells. edge cell has half the ry */
2250
csum = nc / (l[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y);
2251
csum += 1.0/(pk->r_amb_sec_c_per_y) +
2252
1.0/pk->r_pcb_c_per_y + 1.0/(pk->r_pcb2_y + pk->r_pcb);
2253
2254
wsum = 0.0;
2255
for(j=0; j < nc; j++)
2256
wsum += temp->cuboid[pcbidx][0][j];
2257
wsum /= (l[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y);
2258
wsum += c->ambient/(pk->r_amb_sec_c_per_y) +
2259
v[SOLDER_N]/pk->r_pcb_c_per_y + v[PCB_N]/(pk->r_pcb2_y + pk->r_pcb);
2260
delta[PCB_C_N] = fabs(v[PCB_C_N] - wsum / csum);
2261
v[PCB_C_N] = wsum / csum;
2262
2263
wsum = 0.0;
2264
for(j=0; j < nc; j++)
2265
wsum += temp->cuboid[pcbidx][nr-1][j];
2266
wsum /= (l[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y);
2267
wsum += c->ambient/(pk->r_amb_sec_c_per_y) +
2268
v[SOLDER_S]/pk->r_pcb_c_per_y + v[PCB_S]/(pk->r_pcb2_y + pk->r_pcb);
2269
delta[PCB_C_S] = fabs(v[PCB_C_S] - wsum / csum);
2270
v[PCB_C_S] = wsum / csum;
2271
2272
/* PCB inner west/east */
2273
/* partition r_pcb1_x among all the nr grid cells. edge cell has half the rx */
2274
csum = nr / (l[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x);
2275
csum += 1.0/(pk->r_amb_sec_c_per_x) +
2276
1.0/pk->r_pcb_c_per_x + 1.0/(pk->r_pcb2_x + pk->r_pcb);
2277
2278
wsum = 0.0;
2279
for(i=0; i < nr; i++)
2280
wsum += temp->cuboid[pcbidx][i][0];
2281
wsum /= (l[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x);
2282
wsum += c->ambient/(pk->r_amb_sec_c_per_x) +
2283
v[SOLDER_W]/pk->r_pcb_c_per_x + v[PCB_W]/(pk->r_pcb2_x + pk->r_pcb);
2284
delta[PCB_C_W] = fabs(v[PCB_C_W] - wsum / csum);
2285
v[PCB_C_W] = wsum / csum;
2286
2287
wsum = 0.0;
2288
for(i=0; i < nr; i++)
2289
wsum += temp->cuboid[pcbidx][i][nc-1];
2290
wsum /= (l[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x);
2291
wsum += c->ambient/(pk->r_amb_sec_c_per_x) +
2292
v[SOLDER_E]/pk->r_pcb_c_per_x + v[PCB_E]/(pk->r_pcb2_x + pk->r_pcb);
2293
delta[PCB_C_E] = fabs(v[PCB_C_E] - wsum / csum);
2294
v[PCB_C_E] = wsum / csum;
2295
2296
/* solder north/south */
2297
/* partition r_solder1_y among all the nc grid cells. edge cell has half the ry */
2298
csum = nc / (l[solderidx].ry / 2.0 + nc * pk->r_solder1_y);
2299
csum += 1.0/pk->r_solder_per_y + 1.0/pk->r_pcb_c_per_y;
2300
2301
wsum = 0.0;
2302
for(j=0; j < nc; j++)
2303
wsum += temp->cuboid[solderidx][0][j];
2304
wsum /= (l[solderidx].ry / 2.0 + nc * pk->r_solder1_y);
2305
wsum += v[PCB_C_N]/pk->r_pcb_c_per_y + v[SUB_N]/pk->r_solder_per_y;
2306
delta[SOLDER_N] = fabs(v[SOLDER_N] - wsum / csum);
2307
v[SOLDER_N] = wsum / csum;
2308
2309
wsum = 0.0;
2310
for(j=0; j < nc; j++)
2311
wsum += temp->cuboid[solderidx][nr-1][j];
2312
wsum /= (l[solderidx].ry / 2.0 + nc * pk->r_solder1_y);
2313
wsum += v[PCB_C_S]/pk->r_pcb_c_per_y + v[SUB_S]/pk->r_solder_per_y;
2314
delta[SOLDER_S] = fabs(v[SOLDER_S] - wsum / csum);
2315
v[SOLDER_S] = wsum / csum;
2316
2317
/* solder west/east */
2318
/* partition r_solder1_x among all the nr grid cells. edge cell has half the rx */
2319
csum = nr / (l[solderidx].rx / 2.0 + nr * pk->r_solder1_x);
2320
csum += 1.0/pk->r_solder_per_x + 1.0/pk->r_pcb_c_per_x;
2321
2322
wsum = 0.0;
2323
for(i=0; i < nr; i++)
2324
wsum += temp->cuboid[solderidx][i][0];
2325
wsum /= (l[solderidx].rx / 2.0 + nr * pk->r_solder1_x);
2326
wsum += v[PCB_C_W]/pk->r_pcb_c_per_x + v[SUB_W]/pk->r_solder_per_x;
2327
delta[SOLDER_W] = fabs(v[SOLDER_W] - wsum / csum);
2328
v[SOLDER_W] = wsum / csum;
2329
2330
wsum = 0.0;
2331
for(i=0; i < nr; i++)
2332
wsum += temp->cuboid[solderidx][i][nc-1];
2333
wsum /= (l[solderidx].rx / 2.0 + nr * pk->r_solder1_x);
2334
wsum += v[PCB_C_E]/pk->r_pcb_c_per_x + v[SUB_E]/pk->r_solder_per_x;
2335
delta[SOLDER_E] = fabs(v[SOLDER_E] - wsum / csum);
2336
v[SOLDER_E] = wsum / csum;
2337
2338
/* substrate north/south */
2339
/* partition r_sub1_y among all the nc grid cells. edge cell has half the ry */
2340
csum = nc / (l[subidx].ry / 2.0 + nc * pk->r_sub1_y);
2341
csum += 1.0/pk->r_solder_per_y;
2342
2343
wsum = 0.0;
2344
for(j=0; j < nc; j++)
2345
wsum += temp->cuboid[subidx][0][j];
2346
wsum /= (l[subidx].ry / 2.0 + nc * pk->r_sub1_y);
2347
wsum += v[SOLDER_N]/pk->r_solder_per_y;
2348
delta[SUB_N] = fabs(v[SUB_N] - wsum / csum);
2349
v[SUB_N] = wsum / csum;
2350
2351
wsum = 0.0;
2352
for(j=0; j < nc; j++)
2353
wsum += temp->cuboid[subidx][nr-1][j];
2354
wsum /= (l[subidx].ry / 2.0 + nc * pk->r_sub1_y);
2355
wsum += v[SOLDER_S]/pk->r_solder_per_y;
2356
delta[SUB_S] = fabs(v[SUB_S] - wsum / csum);
2357
v[SUB_S] = wsum / csum;
2358
2359
/* substrate west/east */
2360
/* partition r_sub1_x among all the nr grid cells. edge cell has half the rx */
2361
csum = nr / (l[subidx].rx / 2.0 + nr * pk->r_sub1_x);
2362
csum += 1.0/pk->r_solder_per_x;
2363
2364
wsum = 0.0;
2365
for(i=0; i < nr; i++)
2366
wsum += temp->cuboid[subidx][i][0];
2367
wsum /= (l[subidx].rx / 2.0 + nr * pk->r_sub1_x);
2368
wsum += v[SOLDER_W]/pk->r_solder_per_x;
2369
delta[SUB_W] = fabs(v[SUB_W] - wsum / csum);
2370
v[SUB_W] = wsum / csum;
2371
2372
wsum = 0.0;
2373
for(i=0; i < nr; i++)
2374
wsum += temp->cuboid[subidx][i][nc-1];
2375
wsum /= (l[subidx].rx / 2.0 + nr * pk->r_sub1_x);
2376
wsum += v[SOLDER_E]/pk->r_solder_per_x;
2377
delta[SUB_E] = fabs(v[SUB_E] - wsum / csum);
2378
v[SUB_E] = wsum / csum;
2379
}
2380
2381
if (!model->config.model_secondary) {
2382
for(i=0; i < EXTRA; i++) {
2383
if (delta[i] > max)
2384
max = delta[i];
2385
}
2386
} else {
2387
for(i=0; i < EXTRA + EXTRA_SEC; i++) {
2388
if (delta[i] > max)
2389
max = delta[i];
2390
}
2391
}
2392
return max;
2393
}
2394
2395
/* macros for calculating conductances */
2396
/* conductance to the next cell north. zero if on northern boundary */
2397
# define NC(l,n,i,j,nl,nr,nc) ((i > 0) ? (1.0/find_res(model, n, i-1, j, n, i, j)) : 0.0)
2398
/* conductance to the next cell south. zero if on southern boundary */
2399
# define SC(l,n,i,j,nl,nr,nc) ((i < nr-1) ? (1.0/find_res(model, n, i+1, j, n, i, j)) : 0.0)
2400
/* conductance to the next cell east. zero if on eastern boundary */
2401
# define EC(l,n,i,j,nl,nr,nc) ((j < nc-1) ? (1.0/find_res(model, n, i, j+1, n, i, j)) : 0.0)
2402
/* conductance to the next cell west. zero if on western boundary */
2403
# define WC(l,n,i,j,nl,nr,nc) ((j > 0) ? (1.0/find_res(model, n, i, j-1, n, i, j)) : 0.0)
2404
/* conductance to the next cell below. zero if on bottom face */
2405
# define BC(l,n,i,j,nl,nr,nc) ((n < nl-1) ? (1.0/find_res(model, n+1, i, j, n, i, j)) : 0.0)
2406
/* conductance to the next cell above. zero if on top face */
2407
# define AC(l,n,i,j,nl,nr,nc) ((n > 0) ? (1.0/find_res(model, n-1, i, j, n, i, j)) : 0.0)
2408
2409
/* macros for calculating weighted temperatures */
2410
/* weighted T of the next cell north. zero if on northern boundary */
2411
# define NT(l,v,n,i,j,nl,nr,nc) ((i > 0) ? (v[n][i-1][j]/find_res(model, n, i-1, j, n, i, j)) : 0.0)
2412
/* weighted T of the next cell south. zero if on southern boundary */
2413
# define ST(l,v,n,i,j,nl,nr,nc) ((i < nr-1) ? (v[n][i+1][j]/find_res(model, n, i+1, j, n, i, j)) : 0.0)
2414
/* weighted T of the next cell east. zero if on eastern boundary */
2415
# define ET(l,v,n,i,j,nl,nr,nc) ((j < nc-1) ? (v[n][i][j+1]/find_res(model, n, i, j+1, n, i, j)) : 0.0)
2416
/* weighted T of the next cell west. zero if on western boundary */
2417
# define WT(l,v,n,i,j,nl,nr,nc) ((j > 0) ? (v[n][i][j-1]/find_res(model, n, i, j-1, n, i, j)) : 0.0)
2418
/* weighted T of the next cell below. zero if on bottom face */
2419
# define BT(l,v,n,i,j,nl,nr,nc) ((n < nl-1) ? (v[n+1][i][j]/find_res(model, n+1, i, j, n, i, j)) : 0.0)
2420
/* weighted T of the next cell above. zero if on top face */
2421
# define AT(l,v,n,i,j,nl,nr,nc) ((n > 0) ? (v[n-1][i][j]/find_res(model, n-1, i, j, n, i, j)) : 0.0)
2422
2423
//end->BU_3D
2424
2425
/* single steady state iteration of grid solver - silicon part */
2426
double single_iteration_steady_grid(grid_model_t *model, grid_model_vector_t *power,
2427
grid_model_vector_t *temp)
2428
{
2429
int n, i, j;
2430
double prev, delta, max = 0;
2431
/* sum of the conductances */
2432
double csum;
2433
/* weighted sum of temperatures */
2434
double wsum;
2435
2436
/* shortcuts for cell width(cw) and cell height(ch) */
2437
double cw = model->width / model->cols;
2438
double ch = model->height / model->rows;
2439
2440
/* shortcuts */
2441
double ***v = temp->cuboid;
2442
thermal_config_t *c = &model->config;
2443
layer_t *l = model->layers;
2444
int nl = model->n_layers;
2445
int nr = model->rows;
2446
int nc = model->cols;
2447
int spidx, hsidx, subidx, solderidx, pcbidx;
2448
int model_secondary = model->config.model_secondary;
2449
2450
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
2451
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
2452
if (model_secondary) {
2453
subidx = LAYER_SUB;
2454
solderidx = LAYER_SOLDER;
2455
pcbidx = LAYER_PCB;
2456
}
2457
2458
/* for each grid cell */
2459
for(n=0; n < nl; n++) {
2460
for(i=0; i < nr; i++) {
2461
for(j=0; j < nc; j++) {
2462
/* sum the conductances to cells north, south,
2463
* east, west, above and below
2464
*/
2465
csum = NC(l,n,i,j,nl,nr,nc) + SC(l,n,i,j,nl,nr,nc) +
2466
EC(l,n,i,j,nl,nr,nc) + WC(l,n,i,j,nl,nr,nc) +
2467
AC(l,n,i,j,nl,nr,nc) + BC(l,n,i,j,nl,nr,nc);
2468
2469
/* sum of the weighted temperatures of all the neighbours */
2470
wsum = NT(l,v,n,i,j,nl,nr,nc) + ST(l,v,n,i,j,nl,nr,nc) +
2471
ET(l,v,n,i,j,nl,nr,nc) + WT(l,v,n,i,j,nl,nr,nc) +
2472
AT(l,v,n,i,j,nl,nr,nc) + BT(l,v,n,i,j,nl,nr,nc);
2473
2474
/* spreader core is connected to its periphery */
2475
if (n == spidx) {
2476
/* northern boundary - edge cell has half the ry */
2477
if (i == 0) {
2478
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_sp1_y);
2479
wsum += temp->extra[SP_N]/(l[n].ry/2.0 + nc*model->pack.r_sp1_y);
2480
}
2481
/* southern boundary - edge cell has half the ry */
2482
if (i == nr-1) {
2483
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_sp1_y);
2484
wsum += temp->extra[SP_S]/(l[n].ry/2.0 + nc*model->pack.r_sp1_y);
2485
}
2486
/* eastern boundary - edge cell has half the rx */
2487
if (j == nc-1) {
2488
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_sp1_x);
2489
wsum += temp->extra[SP_E]/(l[n].rx/2.0 + nr*model->pack.r_sp1_x);
2490
}
2491
/* western boundary - edge cell has half the rx */
2492
if (j == 0) {
2493
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_sp1_x);
2494
wsum += temp->extra[SP_W]/(l[n].rx/2.0 + nr*model->pack.r_sp1_x);
2495
}
2496
/* heatsink core is connected to its inner periphery and ambient */
2497
} else if (n == hsidx) {
2498
/* all nodes are connected to the ambient */
2499
csum += 1.0/l[n].rz;
2500
wsum += c->ambient/l[n].rz;
2501
/* northern boundary - edge cell has half the ry */
2502
if (i == 0) {
2503
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_hs1_y);
2504
wsum += temp->extra[SINK_C_N]/(l[n].ry/2.0 + nc*model->pack.r_hs1_y);
2505
}
2506
/* southern boundary - edge cell has half the ry */
2507
if (i == nr-1) {
2508
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_hs1_y);
2509
wsum += temp->extra[SINK_C_S]/(l[n].ry/2.0 + nc*model->pack.r_hs1_y);
2510
}
2511
/* eastern boundary - edge cell has half the rx */
2512
if (j == nc-1) {
2513
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_hs1_x);
2514
wsum += temp->extra[SINK_C_E]/(l[n].rx/2.0 + nr*model->pack.r_hs1_x);
2515
}
2516
/* western boundary - edge cell has half the rx */
2517
if (j == 0) {
2518
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_hs1_x);
2519
wsum += temp->extra[SINK_C_W]/(l[n].rx/2.0 + nr*model->pack.r_hs1_x);
2520
}
2521
} else if ((n==subidx) && model->config.model_secondary) {
2522
/* northern boundary - edge cell has half the ry */
2523
if (i == 0) {
2524
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_sub1_y);
2525
wsum += temp->extra[SUB_N]/(l[n].ry/2.0 + nc*model->pack.r_sub1_y);
2526
}
2527
/* southern boundary - edge cell has half the ry */
2528
if (i == nr-1) {
2529
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_sub1_y);
2530
wsum += temp->extra[SUB_S]/(l[n].ry/2.0 + nc*model->pack.r_sub1_y);
2531
}
2532
/* eastern boundary - edge cell has half the rx */
2533
if (j == nc-1) {
2534
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_sub1_x);
2535
wsum += temp->extra[SUB_E]/(l[n].rx/2.0 + nr*model->pack.r_sub1_x);
2536
}
2537
/* western boundary - edge cell has half the rx */
2538
if (j == 0) {
2539
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_sub1_x);
2540
wsum += temp->extra[SUB_W]/(l[n].rx/2.0 + nr*model->pack.r_sub1_x);
2541
}
2542
} else if ((n==solderidx) && model->config.model_secondary) {
2543
/* northern boundary - edge cell has half the ry */
2544
if (i == 0) {
2545
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_solder1_y);
2546
wsum += temp->extra[SOLDER_N]/(l[n].ry/2.0 + nc*model->pack.r_solder1_y);
2547
}
2548
/* southern boundary - edge cell has half the ry */
2549
if (i == nr-1) {
2550
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_solder1_y);
2551
wsum += temp->extra[SOLDER_S]/(l[n].ry/2.0 + nc*model->pack.r_solder1_y);
2552
}
2553
/* eastern boundary - edge cell has half the rx */
2554
if (j == nc-1) {
2555
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_solder1_x);
2556
wsum += temp->extra[SOLDER_E]/(l[n].rx/2.0 + nr*model->pack.r_solder1_x);
2557
}
2558
/* western boundary - edge cell has half the rx */
2559
if (j == 0) {
2560
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_solder1_x);
2561
wsum += temp->extra[SOLDER_W]/(l[n].rx/2.0 + nr*model->pack.r_solder1_x);
2562
}
2563
} else if ((n==pcbidx) && model->config.model_secondary) {
2564
/* all nodes are connected to the ambient */
2565
csum += 1.0/(model->config.r_convec_sec *
2566
(model->config.s_pcb * model->config.s_pcb) / (cw * ch));
2567
wsum += c->ambient/(model->config.r_convec_sec *
2568
(model->config.s_pcb * model->config.s_pcb) / (cw * ch));
2569
/* northern boundary - edge cell has half the ry */
2570
if (i == 0) {
2571
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_pcb1_y);
2572
wsum += temp->extra[PCB_C_N]/(l[n].ry/2.0 + nc*model->pack.r_pcb1_y);
2573
}
2574
/* southern boundary - edge cell has half the ry */
2575
if (i == nr-1) {
2576
csum += 1.0/(l[n].ry/2.0 + nc*model->pack.r_pcb1_y);
2577
wsum += temp->extra[PCB_C_S]/(l[n].ry/2.0 + nc*model->pack.r_pcb1_y);
2578
}
2579
/* eastern boundary - edge cell has half the rx */
2580
if (j == nc-1) {
2581
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_pcb1_x);
2582
wsum += temp->extra[PCB_C_E]/(l[n].rx/2.0 + nr*model->pack.r_pcb1_x);
2583
}
2584
/* western boundary - edge cell has half the rx */
2585
if (j == 0) {
2586
csum += 1.0/(l[n].rx/2.0 + nr*model->pack.r_pcb1_x);
2587
wsum += temp->extra[PCB_C_W]/(l[n].rx/2.0 + nr*model->pack.r_pcb1_x);
2588
}
2589
}
2590
2591
if(model->layers[n].is_microchannel) {
2592
fatal("Steady-state computations with microfluidic cooling require SuperLU package\n");
2593
}
2594
2595
/* update the current cell's temperature */
2596
prev = v[n][i][j];
2597
v[n][i][j] = (power->cuboid[n][i][j] + wsum) / csum;
2598
2599
/* compute maximum delta */
2600
delta = fabs(prev - v[n][i][j]);
2601
if (delta > max)
2602
max = delta;
2603
}
2604
}
2605
}
2606
/* package part of the iteration */
2607
return (MAX(max, single_iteration_steady_pack(model, power, temp)));
2608
}
2609
2610
/* restriction operator for multigrid solver. given a power vector
2611
* corresponding to a fine grid, outputs a vector corresponding
2612
* to one level coarser grid (half the no. of rows and cols)
2613
* NOTE: model->rows and model->cols denote the size of the
2614
* coarser grid
2615
*/
2616
void multigrid_restrict_power(grid_model_t *model, grid_model_vector_t *dst,
2617
grid_model_vector_t *src)
2618
{
2619
/* coarse grid indices */
2620
int n, i, j;
2621
2622
/* grid cells - add the four nearest neighbours */
2623
for(n=0; n < model->n_layers; n++)
2624
for(i=0; i < model->rows; i++)
2625
for(j=0; j < model->cols; j++)
2626
{
2627
dst->cuboid[n][i][j] = (src->cuboid[n][2*i][2*j] +
2628
src->cuboid[n][2*i+1][2*j] +
2629
src->cuboid[n][2*i][2*j+1] +
2630
src->cuboid[n][2*i+1][2*j+1]);
2631
}
2632
/* package nodes - copy them as it is */
2633
if (!model->config.model_secondary)
2634
copy_dvector(dst->extra, src->extra, EXTRA);
2635
else
2636
copy_dvector(dst->extra, src->extra, EXTRA+EXTRA_SEC);
2637
}
2638
2639
/* prolongation(interpolation) operator for multigrid solver.
2640
* given a temperature vector corresponding to a coarse grid,
2641
* outputs a (bi)linearly interpolated vector corresponding
2642
* to one level finer grid (twice the no. of rows and cols)
2643
* NOTE: model->rows and model->cols denote the size of the
2644
* coarser grid
2645
*/
2646
void multigrid_prolong_temp(grid_model_t *model, grid_model_vector_t *dst,
2647
grid_model_vector_t *src)
2648
{
2649
/* coarse grid indices */
2650
int n, i, j;
2651
2652
/* shortcuts */
2653
int nr = model->rows;
2654
int nc = model->cols;
2655
double ***d = dst->cuboid;
2656
double ***s = src->cuboid;
2657
2658
/* For the fine grid cells not on the boundary,
2659
* we want to linearly interpolate in the region
2660
* surrounded by the coarse grid cells (i,j),
2661
* (i+1,j) (i,j+1) and (i+1, j+1). The fine
2662
* grid cells in that region are (2i+1, 2j+1),
2663
* (2i+2, 2j+1), (2i+1, 2j+2) and (2i+2, 2j+2).
2664
* To interpolate bilinearly, we first interpolate
2665
* along one axis and then along the other. In
2666
* each axis, due to the proximity of the fine
2667
* grid cell co-ordinates to one of the coarse
2668
* grid cells, the weights are 3/4 and 1/4 (not
2669
* 1/2 and 1/2) So, repeating them along the
2670
* other axis also results in weights of 9/16,
2671
* 3/16, 3/16 and 1/16
2672
*/
2673
for(n=0; n < model->n_layers; n++)
2674
for(i=0; i < nr-1; i++)
2675
for(j=0; j < nc-1; j++) {
2676
d[n][2*i+1][2*j+1] = 9.0/16.0 * s[n][i][j] +
2677
3.0/16.0 * s[n][i+1][j] +
2678
1.0/16.0 * s[n][i+1][j+1] +
2679
3.0/16.0 * s[n][i][j+1];
2680
d[n][2*i+2][2*j+1] = 3.0/16.0 * s[n][i][j] +
2681
9.0/16.0 * s[n][i+1][j] +
2682
3.0/16.0 * s[n][i+1][j+1] +
2683
1.0/16.0 * s[n][i][j+1];
2684
d[n][2*i+2][2*j+2] = 1.0/16.0 * s[n][i][j] +
2685
3.0/16.0 * s[n][i+1][j] +
2686
9.0/16.0 * s[n][i+1][j+1] +
2687
3.0/16.0 * s[n][i][j+1];
2688
d[n][2*i+1][2*j+2] = 3.0/16.0 * s[n][i][j] +
2689
1.0/16.0 * s[n][i+1][j] +
2690
3.0/16.0 * s[n][i+1][j+1] +
2691
9.0/16.0 * s[n][i][j+1];
2692
}
2693
2694
/* for the cells on the boundary, we perform
2695
* a zeroth order interpolation. i.e., copy
2696
* the nearest coarse grid cell's value
2697
* as it is
2698
*/
2699
for(n=0; n < model->n_layers; n++) {
2700
for(i=0; i < nr; i++) {
2701
d[n][2*i][0] = d[n][2*i+1][0] = s[n][i][0];
2702
d[n][2*i][2*nc-1] = d[n][2*i+1][2*nc-1] = s[n][i][nc-1];
2703
}
2704
for(j=0; j < nc; j++) {
2705
d[n][0][2*j] = d[n][0][2*j+1] = s[n][0][j];
2706
d[n][2*nr-1][2*j] = d[n][2*nr-1][2*j+1] = s[n][nr-1][j];
2707
}
2708
}
2709
2710
/* package nodes - copy them as it is */
2711
if (!model->config.model_secondary)
2712
copy_dvector(dst->extra, src->extra, EXTRA);
2713
else
2714
copy_dvector(dst->extra, src->extra, EXTRA+EXTRA_SEC);
2715
}
2716
2717
/* recursive multigrid solver. it uses the Gauss-Seidel (GS) iterative
2718
* solver to solve at a particular grid granularity. Although GS removes
2719
* high frequency errors in a solution estimate pretty quickly, it
2720
* takes a lot of time to eliminate the low frequency ones. These
2721
* low frequency errors can be eliminated easily by coarsifying the
2722
* grid. This is the core principle of mulrigrid solvers. The version here
2723
* is called "nested iteration". It solves the problem (iteratively using GS)
2724
* first in the coarsest granularity and then utilizes that solution to
2725
* estimate the solution in the next finer grid. This is repeated until
2726
* the solution is found in the finest desired grid. For details, take
2727
* a look at Numerical Recipes in C (2nd edition), sections 19.5 and 19.6
2728
* (http://www.nrbook.com/a/bookcpdf/c19-5.pdf and
2729
* http://www.nrbook.com/a/bookcpdf/c19-6.pdf). Also refer to Prof.
2730
* Jayathi Murthy's ME 608 notes from Purdue - Chapter 8, sections 8.7-8.9.
2731
* (http://meweb.ecn.purdue.edu/~jmurthy/me608/main.pdf - pg. 175-192)
2732
*/
2733
void recursive_multigrid(grid_model_t *model, grid_model_vector_t *power,
2734
grid_model_vector_t *temp)
2735
{
2736
double delta;
2737
#if VERBOSE > 1
2738
unsigned int i = 0;
2739
#endif
2740
grid_model_vector_t *coarse_power, *coarse_temp;
2741
int n;
2742
/* setup heuristic initial temperatures at the coarsest level*/
2743
if (model->rows <= 1 || model->cols <= 1) {
2744
set_heuristic_temp(model, power, temp);
2745
2746
/* for finer grids. use coarser solutions as estimates */
2747
} else {
2748
/* make the grid coarser */
2749
model->rows /= 2;
2750
model->cols /= 2;
2751
for(n=0; n < model->n_layers; n++) {
2752
/* only rz's and c's change. rx's and
2753
* ry's remain the same
2754
*/
2755
model->layers[n].rz /= 4;
2756
if (model->c_ready)
2757
model->layers[n].c *= 4;
2758
}
2759
2760
/* vectors for the coarse grid */
2761
coarse_power = new_grid_model_vector(model);
2762
coarse_temp = new_grid_model_vector(model);
2763
2764
/* coarsen the power vector */
2765
multigrid_restrict_power(model, coarse_power, power);
2766
2767
/* solve recursively */
2768
recursive_multigrid(model, coarse_power, coarse_temp);
2769
2770
/* interpolate the solution to the current fine grid */
2771
multigrid_prolong_temp(model, temp, coarse_temp);
2772
2773
/* cleanup */
2774
free_grid_model_vector(coarse_power);
2775
free_grid_model_vector(coarse_temp);
2776
2777
/* restore the grid */
2778
model->rows *= 2;
2779
model->cols *= 2;
2780
for(n=0; n < model->n_layers; n++) {
2781
model->layers[n].rz *= 4;
2782
if (model->c_ready)
2783
model->layers[n].c /= 4;
2784
}
2785
}
2786
/* refine solution iteratively till convergence */
2787
do {
2788
delta = single_iteration_steady_grid(model, power, temp);
2789
#if VERBOSE > 1
2790
i++;
2791
#endif
2792
} while (!eq(delta, 0));
2793
#if VERBOSE > 1
2794
fprintf(stdout, "no. of iterations for steady state convergence (%d x %d grid): %d\n",
2795
model->rows, model->cols, i);
2796
#endif
2797
}
2798
2799
void steady_state_temp_grid(grid_model_t *model, double *power, double *temp)
2800
{
2801
grid_model_vector_t *p;
2802
double delta;
2803
2804
#if VERBOSE > 1
2805
int num_iterations = 0;
2806
#endif
2807
2808
if (!model->r_ready)
2809
fatal("R model not ready\n");
2810
2811
p = new_grid_model_vector(model);
2812
2813
/* package nodes' power numbers */
2814
set_internal_power_grid(model, power);
2815
2816
/* map the block power numbers to the grid */
2817
xlate_vector_b2g(model, power, p, V_POWER);
2818
2819
#if SUPERLU > 0
2820
/* solve with SuperLU. use grid model's internal
2821
* state vector to store the grid temperatures
2822
*/
2823
direct_SLU(model, p, model->last_steady);
2824
#else
2825
/* solve recursively. use grid model's internal
2826
* state vector to store the grid temperatures
2827
*/
2828
if(model->config.detailed_3D_used){
2829
// For detailed 3D, we do not use multi_grid
2830
set_heuristic_temp(model, p, model->last_steady);
2831
do {
2832
delta = single_iteration_steady_grid(model, p, model->last_steady);
2833
#if VERBOSE > 1
2834
num_iterations++;
2835
#endif
2836
} while (!eq(delta, 0));
2837
#if VERBOSE > 1
2838
fprintf(stdout, "no. of iterations for steady state convergence (%d x %d grid): %d\n",
2839
model->rows, model->cols, num_iterations);
2840
#endif
2841
}
2842
else{
2843
recursive_multigrid(model, p, model->last_steady);
2844
}
2845
#endif
2846
2847
/* map the temperature numbers back */
2848
xlate_temp_g2b(model, temp, model->last_steady);
2849
2850
free_grid_model_vector(p);
2851
}
2852
2853
/* function to access a 1-d array as a 3-d matrix */
2854
#define A3D(array,n,i,j,nl,nr,nc) (array[(n)*(nr)*(nc) + (i)*(nc) + (j)])
2855
2856
/* compute the slope vector for the package nodes */
2857
void slope_fn_pack(grid_model_t *model, double *v, grid_model_vector_t *p, double *dv)
2858
{
2859
int i, j;
2860
/* sum of the currents(power values) */
2861
double psum;
2862
2863
/* shortcuts */
2864
package_RC_t *pk = &model->pack;
2865
thermal_config_t *c = &model->config;
2866
layer_t *l = model->layers;
2867
int nl = model->n_layers;
2868
int nr = model->rows;
2869
int nc = model->cols;
2870
int spidx, hsidx, subidx, solderidx, pcbidx;
2871
int model_secondary = model->config.model_secondary;
2872
2873
/* pointer to the starting address of the extra nodes */
2874
double *x = v + nl*nr*nc;
2875
2876
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
2877
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
2878
if (model_secondary) {
2879
subidx = LAYER_SUB;
2880
solderidx = LAYER_SOLDER;
2881
pcbidx = LAYER_PCB;
2882
}
2883
2884
/* sink outer north/south */
2885
psum = (c->ambient - x[SINK_N])/(pk->r_hs_per + pk->r_amb_per) +
2886
(x[SINK_C_N] - x[SINK_N])/(pk->r_hs2_y + pk->r_hs);
2887
dv[nl*nr*nc + SINK_N] = psum / (pk->c_hs_per + pk->c_amb_per);
2888
psum = (c->ambient - x[SINK_S])/(pk->r_hs_per + pk->r_amb_per) +
2889
(x[SINK_C_S] - x[SINK_S])/(pk->r_hs2_y + pk->r_hs);
2890
dv[nl*nr*nc + SINK_S] = psum / (pk->c_hs_per + pk->c_amb_per);
2891
2892
/* sink outer west/east */
2893
psum = (c->ambient - x[SINK_W])/(pk->r_hs_per + pk->r_amb_per) +
2894
(x[SINK_C_W] - x[SINK_W])/(pk->r_hs2_x + pk->r_hs);
2895
dv[nl*nr*nc + SINK_W] = psum / (pk->c_hs_per + pk->c_amb_per);
2896
psum = (c->ambient - x[SINK_E])/(pk->r_hs_per + pk->r_amb_per) +
2897
(x[SINK_C_E] - x[SINK_E])/(pk->r_hs2_x + pk->r_hs);
2898
dv[nl*nr*nc + SINK_E] = psum / (pk->c_hs_per + pk->c_amb_per);
2899
2900
/* sink inner north/south */
2901
/* partition r_hs1_y among all the nc grid cells. edge cell has half the ry */
2902
psum = 0.0;
2903
for(j=0; j < nc; j++)
2904
psum += (A3D(v,hsidx,0,j,nl,nr,nc) - x[SINK_C_N]);
2905
psum /= (l[hsidx].ry / 2.0 + nc * pk->r_hs1_y);
2906
psum += (c->ambient - x[SINK_C_N])/(pk->r_hs_c_per_y + pk->r_amb_c_per_y) +
2907
(x[SP_N] - x[SINK_C_N])/pk->r_sp_per_y +
2908
(x[SINK_N] - x[SINK_C_N])/(pk->r_hs2_y + pk->r_hs);
2909
dv[nl*nr*nc + SINK_C_N] = psum / (pk->c_hs_c_per_y + pk->c_amb_c_per_y);
2910
2911
psum = 0.0;
2912
for(j=0; j < nc; j++)
2913
psum += (A3D(v,hsidx,nr-1,j,nl,nr,nc) - x[SINK_C_S]);
2914
psum /= (l[hsidx].ry / 2.0 + nc * pk->r_hs1_y);
2915
psum += (c->ambient - x[SINK_C_S])/(pk->r_hs_c_per_y + pk->r_amb_c_per_y) +
2916
(x[SP_S] - x[SINK_C_S])/pk->r_sp_per_y +
2917
(x[SINK_S] - x[SINK_C_S])/(pk->r_hs2_y + pk->r_hs);
2918
dv[nl*nr*nc + SINK_C_S] = psum / (pk->c_hs_c_per_y + pk->c_amb_c_per_y);
2919
2920
/* sink inner west/east */
2921
/* partition r_hs1_x among all the nr grid cells. edge cell has half the rx */
2922
psum = 0.0;
2923
for(i=0; i < nr; i++)
2924
psum += (A3D(v,hsidx,i,0,nl,nr,nc) - x[SINK_C_W]);
2925
psum /= (l[hsidx].rx / 2.0 + nr * pk->r_hs1_x);
2926
psum += (c->ambient - x[SINK_C_W])/(pk->r_hs_c_per_x + pk->r_amb_c_per_x) +
2927
(x[SP_W] - x[SINK_C_W])/pk->r_sp_per_x +
2928
(x[SINK_W] - x[SINK_C_W])/(pk->r_hs2_x + pk->r_hs);
2929
dv[nl*nr*nc + SINK_C_W] = psum / (pk->c_hs_c_per_x + pk->c_amb_c_per_x);
2930
2931
psum = 0.0;
2932
for(i=0; i < nr; i++)
2933
psum += (A3D(v,hsidx,i,nc-1,nl,nr,nc) - x[SINK_C_E]);
2934
psum /= (l[hsidx].rx / 2.0 + nr * pk->r_hs1_x);
2935
psum += (c->ambient - x[SINK_C_E])/(pk->r_hs_c_per_x + pk->r_amb_c_per_x) +
2936
(x[SP_E] - x[SINK_C_E])/pk->r_sp_per_x +
2937
(x[SINK_E] - x[SINK_C_E])/(pk->r_hs2_x + pk->r_hs);
2938
dv[nl*nr*nc + SINK_C_E] = psum / (pk->c_hs_c_per_x + pk->c_amb_c_per_x);
2939
2940
/* spreader north/south */
2941
/* partition r_sp1_y among all the nc grid cells. edge cell has half the ry */
2942
psum = 0.0;
2943
for(j=0; j < nc; j++)
2944
psum += (A3D(v,spidx,0,j,nl,nr,nc) - x[SP_N]);
2945
psum /= (l[spidx].ry / 2.0 + nc * pk->r_sp1_y);
2946
psum += (x[SINK_C_N] - x[SP_N])/pk->r_sp_per_y;
2947
dv[nl*nr*nc + SP_N] = psum / pk->c_sp_per_y;
2948
2949
psum = 0.0;
2950
for(j=0; j < nc; j++)
2951
psum += (A3D(v,spidx,nr-1,j,nl,nr,nc) - x[SP_S]);
2952
psum /= (l[spidx].ry / 2.0 + nc * pk->r_sp1_y);
2953
psum += (x[SINK_C_S] - x[SP_S])/pk->r_sp_per_y;
2954
dv[nl*nr*nc + SP_S] = psum / pk->c_sp_per_y;
2955
2956
/* spreader west/east */
2957
/* partition r_sp1_x among all the nr grid cells. edge cell has half the rx */
2958
psum = 0.0;
2959
for(i=0; i < nr; i++)
2960
psum += (A3D(v,spidx,i,0,nl,nr,nc) - x[SP_W]);
2961
psum /= (l[spidx].rx / 2.0 + nr * pk->r_sp1_x);
2962
psum += (x[SINK_C_W] - x[SP_W])/pk->r_sp_per_x;
2963
dv[nl*nr*nc + SP_W] = psum / pk->c_sp_per_x;
2964
2965
psum = 0.0;
2966
for(i=0; i < nr; i++)
2967
psum += (A3D(v,spidx,i,nc-1,nl,nr,nc) - x[SP_E]);
2968
psum /= (l[spidx].rx / 2.0 + nr * pk->r_sp1_x);
2969
psum += (x[SINK_C_E] - x[SP_E])/pk->r_sp_per_x;
2970
dv[nl*nr*nc + SP_E] = psum / pk->c_sp_per_x;
2971
2972
if (model_secondary) {
2973
/* PCB outer north/south */
2974
psum = (c->ambient - x[PCB_N])/(pk->r_amb_sec_per) +
2975
(x[PCB_C_N] - x[PCB_N])/(pk->r_pcb2_y + pk->r_pcb);
2976
dv[nl*nr*nc + PCB_N] = psum / (pk->c_pcb_per + pk->c_amb_sec_per);
2977
psum = (c->ambient - x[PCB_S])/(pk->r_amb_sec_per) +
2978
(x[PCB_C_S] - x[PCB_S])/(pk->r_pcb2_y + pk->r_pcb);
2979
dv[nl*nr*nc + PCB_S] = psum / (pk->c_pcb_per + pk->c_amb_sec_per);
2980
2981
/* PCB outer west/east */
2982
psum = (c->ambient - x[PCB_W])/(pk->r_amb_sec_per) +
2983
(x[PCB_C_W] - x[PCB_W])/(pk->r_pcb2_x + pk->r_pcb);
2984
dv[nl*nr*nc + PCB_W] = psum / (pk->c_pcb_per + pk->c_amb_sec_per);
2985
psum = (c->ambient - x[PCB_E])/(pk->r_amb_sec_per) +
2986
(x[PCB_C_E] - x[PCB_E])/(pk->r_pcb2_x + pk->r_pcb);
2987
dv[nl*nr*nc + PCB_E] = psum / (pk->c_pcb_per + pk->c_amb_sec_per);
2988
2989
/* PCB inner north/south */
2990
/* partition r_pcb1_y among all the nc grid cells. edge cell has half the ry */
2991
psum = 0.0;
2992
for(j=0; j < nc; j++)
2993
psum += (A3D(v,pcbidx,0,j,nl,nr,nc) - x[PCB_C_N]);
2994
psum /= (l[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y);
2995
psum += (c->ambient - x[PCB_C_N])/(pk->r_amb_sec_c_per_y) +
2996
(x[SOLDER_N] - x[PCB_C_N])/pk->r_pcb_c_per_y +
2997
(x[PCB_N] - x[PCB_C_N])/(pk->r_pcb2_y + pk->r_pcb);
2998
dv[nl*nr*nc + PCB_C_N] = psum / (pk->c_pcb_c_per_y + pk->c_amb_sec_c_per_y);
2999
3000
psum = 0.0;
3001
for(j=0; j < nc; j++)
3002
psum += (A3D(v,pcbidx,nr-1,j,nl,nr,nc) - x[PCB_C_S]);
3003
psum /= (l[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y);
3004
psum += (c->ambient - x[PCB_C_S])/(pk->r_amb_sec_c_per_y) +
3005
(x[SOLDER_S] - x[PCB_C_S])/pk->r_pcb_c_per_y +
3006
(x[PCB_S] - x[PCB_C_S])/(pk->r_pcb2_y + pk->r_pcb);
3007
dv[nl*nr*nc + PCB_C_S] = psum / (pk->c_pcb_c_per_y + pk->c_amb_sec_c_per_y);
3008
3009
/* PCB inner west/east */
3010
/* partition r_pcb1_x among all the nr grid cells. edge cell has half the rx */
3011
psum = 0.0;
3012
for(i=0; i < nr; i++)
3013
psum += (A3D(v,pcbidx,i,0,nl,nr,nc) - x[PCB_C_W]);
3014
psum /= (l[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x);
3015
psum += (c->ambient - x[PCB_C_W])/(pk->r_amb_sec_c_per_x) +
3016
(x[SOLDER_W] - x[PCB_C_W])/pk->r_pcb_c_per_x +
3017
(x[PCB_W] - x[PCB_C_W])/(pk->r_pcb2_x + pk->r_pcb);
3018
dv[nl*nr*nc + PCB_C_W] = psum / (pk->c_pcb_c_per_x + pk->c_amb_sec_c_per_x);
3019
3020
psum = 0.0;
3021
for(i=0; i < nr; i++)
3022
psum += (A3D(v,pcbidx,i,nc-1,nl,nr,nc) - x[PCB_C_E]);
3023
psum /= (l[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x);
3024
psum += (c->ambient - x[PCB_C_E])/(pk->r_amb_sec_c_per_x) +
3025
(x[SOLDER_E] - x[PCB_C_E])/pk->r_pcb_c_per_x +
3026
(x[PCB_E] - x[PCB_C_E])/(pk->r_pcb2_x + pk->r_pcb);
3027
dv[nl*nr*nc + PCB_C_E] = psum / (pk->c_pcb_c_per_x + pk->c_amb_sec_c_per_x);
3028
3029
/* solder ball north/south */
3030
/* partition r_solder1_y among all the nc grid cells. edge cell has half the ry */
3031
psum = 0.0;
3032
for(j=0; j < nc; j++)
3033
psum += (A3D(v,solderidx,0,j,nl,nr,nc) - x[SOLDER_N]);
3034
psum /= (l[solderidx].ry / 2.0 + nc * pk->r_solder1_y);
3035
psum += (x[PCB_C_N] - x[SOLDER_N])/pk->r_pcb_c_per_y;
3036
dv[nl*nr*nc + SOLDER_N] = psum / pk->c_solder_per_y;
3037
3038
psum = 0.0;
3039
for(j=0; j < nc; j++)
3040
psum += (A3D(v,solderidx,nr-1,j,nl,nr,nc) - x[SOLDER_S]);
3041
psum /= (l[solderidx].ry / 2.0 + nc * pk->r_solder1_y);
3042
psum += (x[PCB_C_S] - x[SOLDER_S])/pk->r_pcb_c_per_y;
3043
dv[nl*nr*nc + SOLDER_S] = psum / pk->c_solder_per_y;
3044
3045
/* solder ball west/east */
3046
/* partition r_solder1_x among all the nr grid cells. edge cell has half the rx */
3047
psum = 0.0;
3048
for(i=0; i < nr; i++)
3049
psum += (A3D(v,solderidx,i,0,nl,nr,nc) - x[SOLDER_W]);
3050
psum /= (l[solderidx].rx / 2.0 + nr * pk->r_solder1_x);
3051
psum += (x[PCB_C_W] - x[SOLDER_W])/pk->r_pcb_c_per_x;
3052
dv[nl*nr*nc + SOLDER_W] = psum / pk->c_solder_per_x;
3053
3054
psum = 0.0;
3055
for(i=0; i < nr; i++)
3056
psum += (A3D(v,solderidx,i,nc-1,nl,nr,nc) - x[SOLDER_E]);
3057
psum /= (l[solderidx].rx / 2.0 + nr * pk->r_solder1_x);
3058
psum += (x[PCB_C_E] - x[SOLDER_E])/pk->r_pcb_c_per_x;
3059
dv[nl*nr*nc + SOLDER_E] = psum / pk->c_solder_per_x;
3060
3061
/* package substrate north/south */
3062
/* partition r_sub1_y among all the nc grid cells. edge cell has half the ry */
3063
psum = 0.0;
3064
for(j=0; j < nc; j++)
3065
psum += (A3D(v,subidx,0,j,nl,nr,nc) - x[SUB_N]);
3066
psum /= (l[subidx].ry / 2.0 + nc * pk->r_sub1_y);
3067
psum += (x[SOLDER_N] - x[SUB_N])/pk->r_solder_per_y;
3068
dv[nl*nr*nc + SUB_N] = psum / pk->c_sub_per_y;
3069
3070
psum = 0.0;
3071
for(j=0; j < nc; j++)
3072
psum += (A3D(v,subidx,nr-1,j,nl,nr,nc) - x[SUB_S]);
3073
psum /= (l[subidx].ry / 2.0 + nc * pk->r_sub1_y);
3074
psum += (x[SOLDER_S] - x[SUB_S])/pk->r_solder_per_y;
3075
dv[nl*nr*nc + SUB_S] = psum / pk->c_sub_per_y;
3076
3077
/* sub ball west/east */
3078
/* partition r_sub1_x among all the nr grid cells. edge cell has half the rx */
3079
psum = 0.0;
3080
for(i=0; i < nr; i++)
3081
psum += (A3D(v,subidx,i,0,nl,nr,nc) - x[SUB_W]);
3082
psum /= (l[subidx].rx / 2.0 + nr * pk->r_sub1_x);
3083
psum += (x[SOLDER_W] - x[SUB_W])/pk->r_solder_per_x;
3084
dv[nl*nr*nc + SUB_W] = psum / pk->c_sub_per_x;
3085
3086
psum = 0.0;
3087
for(i=0; i < nr; i++)
3088
psum += (A3D(v,subidx,i,nc-1,nl,nr,nc) - x[SUB_E]);
3089
psum /= (l[subidx].rx / 2.0 + nr * pk->r_sub1_x);
3090
psum += (x[SOLDER_E] - x[SUB_E])/pk->r_solder_per_x;
3091
dv[nl*nr*nc + SUB_E] = psum / pk->c_sub_per_x;
3092
}
3093
}
3094
3095
/* macros for calculating currents(power values) */
3096
/* current(power) from the next cell north. zero if on northern boundary */
3097
# define NP(l,v,n,i,j,nl,nr,nc) ((i > 0) ? ((A3D(v,n,i-1,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i-1, j, n, i, j)) : 0.0)
3098
/* current(power) from the next cell south. zero if on southern boundary */
3099
# define SP(l,v,n,i,j,nl,nr,nc) ((i < nr-1) ? ((A3D(v,n,i+1,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i+1, j, n, i, j)) : 0.0)
3100
/* current(power) from the next cell east. zero if on eastern boundary */
3101
# define EP(l,v,n,i,j,nl,nr,nc) ((j < nc-1) ? ((A3D(v,n,i,j+1,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i, j+1, n, i, j)) : 0.0)
3102
/* current(power) from the next cell west. zero if on western boundary */
3103
# define WP(l,v,n,i,j,nl,nr,nc) ((j > 0) ? ((A3D(v,n,i,j-1,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i, j-1, n, i, j)) : 0.0)
3104
/* current(power) from the next cell below. zero if on bottom face */
3105
# define BP(l,v,n,i,j,nl,nr,nc) ((n < nl-1) ? ((A3D(v,n+1,i,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n+1, i, j, n, i, j)) : 0.0)
3106
/* current(power) from the next cell above. zero if on top face */
3107
# define AP(l,v,n,i,j,nl,nr,nc) ((n > 0) ? ((A3D(v,n-1,i,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n-1, i, j, n, i, j)) : 0.0)
3108
3109
//BU_3D: These are the same macros as above except that they have to check
3110
//for a resistivity value first since the lc model is not uniform across the layer
3111
/* current(power) from the next cell north. zero if on northern boundary */
3112
# define NP_det3D(l,v,n,i,j,nl,nr,nc) ((i > 0) ? ((A3D(v,n,i-1,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i-1, j, n, i, j)) : 0.0)
3113
/* current(power) from the next cell south. zero if on southern boundary */
3114
# define SP_det3D(l,v,n,i,j,nl,nr,nc) ((i < nr-1) ? ((A3D(v,n,i+1,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i+1, j, n, i, j)) : 0.0)
3115
/* current(power) from the next cell east. zero if on eastern boundary */
3116
# define EP_det3D(l,v,n,i,j,nl,nr,nc) ((j < nc-1) ? ((A3D(v,n,i,j+1,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i, j+1, n, i, j)) : 0.0)
3117
/* current(power) from the next cell west. zero if on western boundary */
3118
# define WP_det3D(l,v,n,i,j,nl,nr,nc) ((j > 0) ? ((A3D(v,n,i,j-1,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n, i, j-1, n, i, j)) : 0.0)
3119
/* current(power) from the next cell below. zero if on bottom face */
3120
# define BP_det3D(l,v,n,i,j,nl,nr,nc) ((n < nl-1) ? ((A3D(v,n+1,i,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n+1, i, j, n, i, j)) : 0.0)
3121
/* current(power) from the next cell above. zero if on top face */
3122
# define AP_det3D(l,v,n,i,j,nl,nr,nc) ((n > 0) ? ((A3D(v,n-1,i,j,nl,nr,nc)-A3D(v,n,i,j,nl,nr,nc))/find_res(model, n-1, i, j, n, i, j)) : 0.0)
3123
//end->BU_3D
3124
3125
3126
/* compute the slope vector for the grid cells. the transient
3127
* equation is CdV + sum{(T - Ti)/Ri} = P
3128
* so, slope = dV = [P + sum{(Ti-T)/Ri}]/C
3129
*/
3130
void slope_fn_grid(grid_model_t *model, double *v, grid_model_vector_t *p, double *dv)
3131
{
3132
int n, i, j;
3133
/* sum of the currents(power values) */
3134
double psum;
3135
3136
/* shortcuts for cell width(cw) and cell height(ch) */
3137
double cw = model->width / model->cols;
3138
double ch = model->height / model->rows;
3139
3140
/* shortcuts */
3141
thermal_config_t *c = &model->config;
3142
layer_t *l = model->layers;
3143
microchannel_config_t *uconf;
3144
int nl = model->n_layers;
3145
int nr = model->rows;
3146
int nc = model->cols;
3147
int spidx, hsidx, subidx, solderidx, pcbidx;
3148
int model_secondary = model->config.model_secondary;
3149
3150
/* pointer to the starting address of the extra nodes */
3151
double *x = v + nl*nr*nc;
3152
3153
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
3154
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
3155
3156
if (model_secondary) {
3157
subidx = LAYER_SUB;
3158
solderidx = LAYER_SOLDER;
3159
pcbidx = LAYER_PCB;
3160
}
3161
3162
/* for each grid cell */
3163
for(n=0; n < nl; n++)
3164
for(i=0; i < nr; i++)
3165
for(j=0; j < nc; j++) {
3166
/* sum the currents(power values) to cells north, south,
3167
* east, west, above and below
3168
*/
3169
// BU_3D: uses grid specific values for all layers
3170
// spreader and heat sink layers will use uniform R
3171
if(model->config.detailed_3D_used == 1){
3172
psum = NP_det3D(l,v,n,i,j,nl,nr,nc) + SP_det3D(l,v,n,i,j,nl,nr,nc) +
3173
EP_det3D(l,v,n,i,j,nl,nr,nc) + WP_det3D(l,v,n,i,j,nl,nr,nc) +
3174
AP_det3D(l,v,n,i,j,nl,nr,nc) + BP_det3D(l,v,n,i,j,nl,nr,nc);
3175
}
3176
else{
3177
psum = NP(l,v,n,i,j,nl,nr,nc) + SP(l,v,n,i,j,nl,nr,nc) +
3178
EP(l,v,n,i,j,nl,nr,nc) + WP(l,v,n,i,j,nl,nr,nc) +
3179
AP(l,v,n,i,j,nl,nr,nc) + BP(l,v,n,i,j,nl,nr,nc);
3180
}//end->BU_3D
3181
////fprintf(stderr, "Temperature Sum for cell (%d, %d, %d): %e\n", n, i, j, psum);
3182
/* spreader core is connected to its periphery */
3183
if (n == spidx) {
3184
/* northern boundary - edge cell has half the ry */
3185
if (i == 0)
3186
psum += (x[SP_N] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_sp1_y);
3187
/* southern boundary - edge cell has half the ry */
3188
if (i == nr-1)
3189
psum += (x[SP_S] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_sp1_y);
3190
/* eastern boundary - edge cell has half the rx */
3191
if (j == nc-1)
3192
psum += (x[SP_E] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_sp1_x);
3193
/* western boundary - edge cell has half the rx */
3194
if (j == 0)
3195
psum += (x[SP_W] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_sp1_x);
3196
/* heatsink core is connected to its inner periphery and ambient */
3197
} else if (n == hsidx) {
3198
/* all nodes are connected to the ambient */
3199
psum += (c->ambient - A3D(v,n,i,j,nl,nr,nc))/l[n].rz;
3200
/* northern boundary - edge cell has half the ry */
3201
if (i == 0)
3202
psum += (x[SINK_C_N] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_hs1_y);
3203
/* southern boundary - edge cell has half the ry */
3204
if (i == nr-1)
3205
psum += (x[SINK_C_S] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_hs1_y);
3206
/* eastern boundary - edge cell has half the rx */
3207
if (j == nc-1)
3208
psum += (x[SINK_C_E] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_hs1_x);
3209
/* western boundary - edge cell has half the rx */
3210
if (j == 0)
3211
psum += (x[SINK_C_W] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_hs1_x);
3212
} else if (n == pcbidx && model_secondary) {
3213
/* all nodes are connected to the ambient */
3214
psum += (c->ambient - A3D(v,n,i,j,nl,nr,nc))/(model->config.r_convec_sec *
3215
(model->config.s_pcb * model->config.s_pcb) / (cw * ch));
3216
/* northern boundary - edge cell has half the ry */
3217
if (i == 0)
3218
psum += (x[PCB_C_N] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_pcb1_y);
3219
/* southern boundary - edge cell has half the ry */
3220
if (i == nr-1)
3221
psum += (x[PCB_C_S] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_pcb1_y);
3222
/* eastern boundary - edge cell has half the rx */
3223
if (j == nc-1)
3224
psum += (x[PCB_C_E] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_pcb1_x);
3225
/* western boundary - edge cell has half the rx */
3226
if (j == 0)
3227
psum += (x[PCB_C_W] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_pcb1_x);
3228
} else if (n == subidx && model_secondary) {
3229
/* northern boundary - edge cell has half the ry */
3230
if (i == 0)
3231
psum += (x[SUB_N] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_sub1_y);
3232
/* southern boundary - edge cell has half the ry */
3233
if (i == nr-1)
3234
psum += (x[SUB_S] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_sub1_y);
3235
/* eastern boundary - edge cell has half the rx */
3236
if (j == nc-1)
3237
psum += (x[SUB_E] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_sub1_x);
3238
/* western boundary - edge cell has half the rx */
3239
if (j == 0)
3240
psum += (x[SUB_W] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_sub1_x);
3241
} else if (n == solderidx && model_secondary) {
3242
/* northern boundary - edge cell has half the ry */
3243
if (i == 0)
3244
psum += (x[SOLDER_N] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_solder1_y);
3245
/* southern boundary - edge cell has half the ry */
3246
if (i == nr-1)
3247
psum += (x[SOLDER_S] - A3D(v,n,i,j,nl,nr,nc))/(l[n].ry/2.0 + nc*model->pack.r_solder1_y);
3248
/* eastern boundary - edge cell has half the rx */
3249
if (j == nc-1)
3250
psum += (x[SOLDER_E] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_solder1_x);
3251
/* western boundary - edge cell has half the rx */
3252
if (j == 0)
3253
psum += (x[SOLDER_W] - A3D(v,n,i,j,nl,nr,nc))/(l[n].rx/2.0 + nr*model->pack.r_solder1_x);
3254
}
3255
3256
if(model->layers[n].is_microchannel) {
3257
/* I'm making the assumption that inlets and outlets cannot exist at corners */
3258
3259
uconf = model->layers[n].microchannel_config;
3260
double coeff;
3261
if(IS_FLUID_CELL(uconf, i, j)) {
3262
//fprintf(stderr, "[%d, %d]: Fluid cell\n", i, j);
3263
/* northern cell */
3264
if(i > 0) {
3265
if(IS_FLUID_CELL(uconf, i-1, j)) {
3266
coeff = uconf->coolant_capac * flow_rate(uconf, i-1, j, i, j);
3267
//fprintf(stderr, "[%d, %d], Fluid cell to the north\n", i, j);
3268
//fprintf(stderr, "[%d, %d], Temp: %.6lf, N Temp: %.6lf, flow_rate = %.6lf\n", i, j, A3D(v,n,i,j,nl,nr,nc), A3D(v,n,i-1,j,nl,nr,nc), flow_rate(uconf, i-1, j, i, j));
3269
//fprintf(stderr, "psum BEFORE: %e\n", psum);
3270
psum += coeff * ((A3D(v,n,i-1,j,nl,nr,nc) + A3D(v,n,i,j,nl,nr,nc)) / 2.0);
3271
//fprintf(stderr, "psum AFTER: %e\n", psum);
3272
}
3273
}
3274
3275
/* southern cell */
3276
if(i < nr - 1) {
3277
if(IS_FLUID_CELL(uconf, i+1, j)) {
3278
coeff = uconf->coolant_capac * flow_rate(uconf, i+1, j, i, j);
3279
//fprintf(stderr, "[%d, %d], Fluid cell to the south\n", i, j);
3280
//fprintf(stderr, "[%d, %d], Temp: %.6lf, S Temp: %.6lf, flow_rate = %.6lf\n", i, j, A3D(v,n,i,j,nl,nr,nc), A3D(v,n,i+1,j,nl,nr,nc), flow_rate(uconf, i+1, j, i, j));
3281
//fprintf(stderr, "psum BEFORE: %e\n", psum);
3282
psum += coeff * ((A3D(v,n,i+1,j,nl,nr,nc) + A3D(v,n,i,j,nl,nr,nc)) / 2.0);
3283
//fprintf(stderr, "psum AFTER: %e\n", psum);
3284
}
3285
}
3286
3287
/* western cell */
3288
if(j > 0) {
3289
if(IS_FLUID_CELL(uconf, i, j-1)) {
3290
coeff = uconf->coolant_capac * flow_rate(uconf, i, j-1, i, j);
3291
//fprintf(stderr, "[%d, %d], Fluid cell to the west\n", i, j);
3292
//fprintf(stderr, "[%d, %d], Temp: %.6lf, W Temp: %.6lf, flow_rate = %.6lf\n", i, j, A3D(v,n,i,j,nl,nr,nc), A3D(v,n,i,j-1,nl,nr,nc), flow_rate(uconf, i, j-1, i, j));
3293
//fprintf(stderr, "psum BEFORE: %.6lf\n", psum);
3294
psum += coeff * ((A3D(v,n,i,j-1,nl,nr,nc) + A3D(v,n,i,j,nl,nr,nc)) / 2.0);
3295
//fprintf(stderr, "psum AFTER: %e\n", psum);
3296
}
3297
}
3298
3299
/* eastern cell */
3300
if(j < nc - 1) {
3301
if(IS_FLUID_CELL(uconf, i, j+1)) {
3302
coeff = uconf->coolant_capac * flow_rate(uconf, i, j+1, i, j);
3303
//fprintf(stderr, "[%d, %d], Fluid cell to the east\n", i, j);
3304
//fprintf(stderr, "[%d, %d], Temp: %.6lf, E Temp: %.6lf, flow_rate = %.6lf\n", i, j, A3D(v,n,i,j,nl,nr,nc), A3D(v,n,i,j+1,nl,nr,nc), flow_rate(uconf, i, j+1, i, j));
3305
//fprintf(stderr, "psum BEFORE: %e\n", psum);
3306
psum += coeff * ((A3D(v,n,i,j+1,nl,nr,nc) + A3D(v,n,i,j,nl,nr,nc)) / 2.0);
3307
//fprintf(stderr, "psum AFTER: %e\n", psum);
3308
}
3309
}
3310
}
3311
3312
if(IS_INLET_CELL(uconf, i, j)) {
3313
//fprintf(stderr, "[%d, %d]: INLET cell\n", i, j);
3314
double inlet_flow_rate = 0;
3315
3316
/* northern inlet*/
3317
if(i == 0) {
3318
//fprintf(stderr, "[%d, %d]: Northern Inlet\n", i, j);
3319
3320
/* Add flow rates to other cells to determine inlet flow rate */
3321
3322
// Check western cell
3323
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
3324
3325
inlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
3326
//fprintf(stderr, "[%d, %d]: Northern Inlet. Fluid cell to the west\n", i, j);
3327
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j-1, i, j), inlet_flow_rate);
3328
}
3329
3330
// Check eastern cell
3331
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
3332
3333
inlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
3334
//fprintf(stderr, "[%d, %d]: Northern Inlet. Fluid cell to the east\n", i, j);
3335
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j+1, i, j), inlet_flow_rate);
3336
}
3337
3338
// Check southern cell
3339
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
3340
3341
inlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
3342
//fprintf(stderr, "[%d, %d]: Northern Inlet. Fluid cell to the south\n", i, j);
3343
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i+1, j, i, j), inlet_flow_rate);
3344
}
3345
}
3346
3347
/* southern inlet */
3348
else if(i == nr - 1) {
3349
//fprintf(stderr, "[%d, %d]: Southern Inlet\n", i, j);
3350
3351
/* Add flow rates to other cells to determine inlet flow rate */
3352
3353
// Check western cell
3354
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
3355
3356
inlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
3357
//fprintf(stderr, "[%d, %d]: Southern Inlet. Fluid cell to the west\n", i, j);
3358
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j-1, i, j), inlet_flow_rate);
3359
}
3360
3361
// Check eastern cell
3362
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
3363
3364
inlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
3365
//fprintf(stderr, "[%d, %d]: Southern Inlet. Fluid cell to the east\n", i, j);
3366
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j+1, i, j), inlet_flow_rate);
3367
}
3368
3369
// Check northern cell
3370
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
3371
3372
inlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
3373
//fprintf(stderr, "[%d, %d]: Southern Inlet. Fluid cell to the north\n", i, j);
3374
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i-1, j, i, j), inlet_flow_rate);
3375
}
3376
}
3377
3378
/* western inlet */
3379
else if(j == 0) {
3380
//fprintf(stderr, "[%d, %d]: Western Inlet\n", i, j);
3381
3382
/* Add flow rates to other cells to determine inlet flow rate */
3383
3384
// Check eastern cell
3385
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
3386
3387
inlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
3388
//fprintf(stderr, "[%d, %d]: Western Inlet. Fluid cell to the east\n", i, j);
3389
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j+1, i, j), inlet_flow_rate);
3390
}
3391
3392
// Check northern cell
3393
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
3394
3395
inlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
3396
//fprintf(stderr, "[%d, %d]: Western Inlet. Fluid cell to the north\n", i, j);
3397
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i-1, j, i, j), inlet_flow_rate);
3398
}
3399
3400
// Check southern cell
3401
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
3402
3403
inlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
3404
//fprintf(stderr, "[%d, %d]: Western Inlet. Fluid cell to the south\n", i, j);
3405
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i+1, j, i, j), inlet_flow_rate);
3406
}
3407
}
3408
3409
/* eastern inlet */
3410
else if (j == nc - 1) {
3411
//fprintf(stderr, "[%d, %d]: Eastern Inlet\n", i, j);
3412
3413
/* Add flow rates to other cells to determine inlet flow rate */
3414
3415
// Check western cell
3416
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
3417
3418
inlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
3419
//fprintf(stderr, "[%d, %d]: Eastern Inlet. Fluid cell to the west\n", i, j);
3420
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j-1, i, j), inlet_flow_rate);
3421
}
3422
3423
// Check northern cell
3424
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
3425
3426
inlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
3427
//fprintf(stderr, "[%d, %d]: Eastern Inlet. Fluid cell to the north\n", i, j);
3428
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i-1, j, i, j), inlet_flow_rate);
3429
}
3430
3431
// Check southern cell
3432
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
3433
3434
inlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
3435
//fprintf(stderr, "[%d, %d]: Eastern Inlet. Fluid cell to the south\n", i, j);
3436
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, inlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i+1, j, i, j), inlet_flow_rate);
3437
}
3438
}
3439
3440
//fprintf(stderr, "Processed all inlets\n");
3441
//fprintf(stderr, "Flow rate = %e mL/min\n", inlet_flow_rate * 6e7);
3442
//fprintf(stderr, "C_v = %e, inlet_flow_rate = %e, inlet_temp = %e\n", uconf->coolant_capac, inlet_flow_rate, uconf->inlet_temperature);
3443
//fprintf(stderr, " psum = %e BEFORE\n", psum);
3444
3445
// The inlet_flow_rate is negative because it is equal to all of the fluid flowing out of the inlet
3446
// Here we multiply by -1 to make it positive since the fluid flowing into the inlet is positive.
3447
inlet_flow_rate *= -1;
3448
psum += uconf->coolant_capac * inlet_flow_rate * uconf->inlet_temperature;
3449
//fprintf(stderr, " psum = %e AFTER\n", psum);
3450
}
3451
3452
else if(IS_OUTLET_CELL(uconf, i, j)) {
3453
////fprintf(stderr, "[%d, %d]: OUTLET cell\n", i, j);
3454
double outlet_flow_rate = 0;
3455
3456
/* northern outlet*/
3457
if(i == 0) {
3458
//fprintf(stderr, "[%d, %d]: Northern Outlet\n", i, j);
3459
3460
/* Add flow rates to other cells to determine outlet flow rate */
3461
3462
// Check western cell
3463
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
3464
3465
outlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
3466
//fprintf(stderr, "[%d, %d]: Northern Outlet. Fluid cell to the west\n", i, j);
3467
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j-1, i, j), outlet_flow_rate);
3468
}
3469
3470
// Check eastern cell
3471
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
3472
3473
outlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
3474
//fprintf(stderr, "[%d, %d]: Northern Outlet. Fluid cell to the east\n", i, j);
3475
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j+1, i, j), outlet_flow_rate);
3476
}
3477
3478
// Check southern cell
3479
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
3480
3481
outlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
3482
//fprintf(stderr, "[%d, %d]: Northern Outlet. Fluid cell to the south\n", i, j);
3483
//fprintf(stderr, "[%d, %d]: flow_rate = %e, outlet_flow_rate = %e\n", i, j, flow_rate(uconf, i+1, j, i, j), outlet_flow_rate);
3484
}
3485
}
3486
3487
/* southern outlet */
3488
else if(i == nr - 1) {
3489
//fprintf(stderr, "[%d, %d]: Southern Outlet\n", i, j);
3490
3491
/* Add flow rates to other cells to determine outlet flow rate */
3492
3493
// Check western cell
3494
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
3495
3496
outlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
3497
//fprintf(stderr, "[%d, %d]: Southern Outlet. Fluid cell to the west\n", i, j);
3498
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j-1, i, j), outlet_flow_rate);
3499
}
3500
3501
// Check eastern cell
3502
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
3503
3504
outlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
3505
//fprintf(stderr, "[%d, %d]: Southern Outlet. Fluid cell to the east\n", i, j);
3506
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j+1, i, j), outlet_flow_rate);
3507
}
3508
3509
// Check northern cell
3510
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
3511
3512
outlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
3513
//fprintf(stderr, "[%d, %d]: Southern Outlet. Fluid cell to the north\n", i, j);
3514
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i-1, j, i, j), outlet_flow_rate);
3515
}
3516
}
3517
3518
/* western outlet */
3519
else if(j == 0) {
3520
//fprintf(stderr, "[%d, %d]: Western Outlet\n", i, j);
3521
3522
/* Add flow rates to other cells to determine outlet flow rate */
3523
3524
// Check eastern cell
3525
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
3526
3527
outlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
3528
//fprintf(stderr, "[%d, %d]: Western Outlet. Fluid cell to the east\n", i, j);
3529
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j+1, i, j), outlet_flow_rate);
3530
}
3531
3532
// Check northern cell
3533
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
3534
3535
outlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
3536
//fprintf(stderr, "[%d, %d]: Western Outlet. Fluid cell to the north\n", i, j);
3537
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i-1, j, i, j), outlet_flow_rate);
3538
}
3539
3540
// Check southern cell
3541
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
3542
3543
outlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
3544
//fprintf(stderr, "[%d, %d]: Western Outlet. Fluid cell to the south\n", i, j);
3545
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i+1, j, i, j), outlet_flow_rate);
3546
}
3547
}
3548
3549
/* eastern outlet */
3550
else if (j == nc - 1) {
3551
//fprintf(stderr, "[%d, %d]: Eastern Outlet\n", i, j);
3552
3553
/* Add flow rates to other cells to determine outlet flow rate */
3554
3555
// Check western cell
3556
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
3557
3558
outlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
3559
//fprintf(stderr, "[%d, %d]: Eastern Outlet. Fluid cell to the west\n", i, j);
3560
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i, j-1, i, j), outlet_flow_rate);
3561
}
3562
3563
// Check northern cell
3564
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
3565
3566
outlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
3567
//fprintf(stderr, "[%d, %d]: Eastern Outlet. Fluid cell to the north\n", i, j);
3568
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i-1, j, i, j), outlet_flow_rate);
3569
}
3570
3571
// Check southern cell
3572
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
3573
3574
outlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
3575
//fprintf(stderr, "[%d, %d]: Eastern Outlet. Fluid cell to the south\n", i, j);
3576
//fprintf(stderr, "[%d, %d]: flow_rate = %.6lf, outlet_flow_rate = %.6lf\n", i, j, flow_rate(uconf, i+1, j, i, j), outlet_flow_rate);
3577
}
3578
}
3579
3580
//fprintf(stderr, "Processed all outlets\n");
3581
//fprintf(stderr, " Cv = %e, outlet_flow_rate = %e, T = %e\n", uconf->coolant_capac, outlet_flow_rate, A3D(v,n,i,j,nl,nr,nc));
3582
//fprintf(stderr, " psum = %e BEFORE\n", psum);
3583
3584
// The outlet_flow_rate is positive since I've added up everything flowing into me. However, we are now taking into account
3585
// what is flowing out of the outlet, so we negate it.
3586
outlet_flow_rate *= -1;
3587
psum += uconf->coolant_capac * outlet_flow_rate * A3D(v,n,i,j,nl,nr,nc);
3588
//fprintf(stderr, " psum = %e AFTER\n", psum);
3589
}
3590
}
3591
3592
/* update the current cell's temperature */
3593
if(model->config.detailed_3D_used == 1)//BU_3D: use find_cap_3D is detailed_3D model is used.
3594
A3D(dv,n,i,j,nl,nr,nc) = (p->cuboid[n][i][j] + psum) / find_cap_3D(n, i, j, model);
3595
else
3596
A3D(dv,n,i,j,nl,nr,nc) = (p->cuboid[n][i][j] + psum) / l[n].c;
3597
3598
}
3599
/* for each grid cell */
3600
slope_fn_pack(model, v, p, dv);
3601
}
3602
3603
void compute_temp_grid(grid_model_t *model, double *power, double *temp, double time_elapsed)
3604
{
3605
double t, h, new_h;
3606
int extra_nodes;
3607
grid_model_vector_t *p;
3608
3609
if (model->config.model_secondary)
3610
extra_nodes = EXTRA + EXTRA_SEC;
3611
else
3612
extra_nodes = EXTRA;
3613
3614
if (!model->r_ready || !model->c_ready)
3615
fatal("grid model not ready\n");
3616
3617
p = new_grid_model_vector(model);
3618
3619
/* package nodes' power numbers */
3620
set_internal_power_grid(model, power);
3621
3622
/* map the block power/temp numbers to the grid */
3623
xlate_vector_b2g(model, power, p, V_POWER);
3624
3625
/* if temp is NULL, re-use the temperature from the
3626
* last call. otherwise, translate afresh and remember
3627
* the grid and block temperature arrays for future use
3628
*/
3629
if (temp != NULL) {
3630
xlate_vector_b2g(model, temp, model->last_trans, V_TEMP);
3631
model->last_temp = temp;
3632
}
3633
3634
#if SUPERLU > 0
3635
int nl = model->n_layers;
3636
int nr = model->rows;
3637
int nc = model->cols;
3638
h = time_elapsed;
3639
3640
SuperMatrix *G;
3641
diagonal_matrix_t *C;
3642
double *T, *P;
3643
3644
// We only need to compute G and C in the first call
3645
static int first_call = TRUE;
3646
if(first_call) {
3647
model->G = build_transient_grid_matrix(model);
3648
model->C = build_diagonal_matrix(model);
3649
first_call = FALSE;
3650
}
3651
3652
G = &(model->G);
3653
C = model->C;
3654
T = model->last_trans->cuboid[0][0];
3655
P = build_transient_power_vector(model, p);
3656
3657
if(MAKE_CSVS) {
3658
vectorTocsv("P.csv", nl*nr*nc + EXTRA, P);
3659
vectorTocsv("T.csv", nl*nr*nc + EXTRA, T);
3660
}
3661
3662
backward_euler(G, C, T, P, &h, T);
3663
3664
#else
3665
3666
/* Obtain temp at time (t+time_elapsed).
3667
* Instead of getting the temperature at t+time_elapsed directly, we
3668
* do it in multiple steps with the correct step size at each time
3669
* provided by rk4.
3670
*/
3671
3672
#if VERBOSE > 1
3673
int rk4_calls = 0;
3674
#endif
3675
3676
for (t = 0, new_h = MIN_STEP; t < time_elapsed && new_h >= MIN_STEP*DELTA; t+=h) {
3677
h = new_h;
3678
/* pass the entire grid and the tail of package nodes
3679
* as a 1-d array
3680
*/
3681
new_h = rk4(model, model->last_trans->cuboid[0][0], p,
3682
/* array size = grid size + EXTRA */
3683
model->rows * model->cols * model->n_layers + extra_nodes, &h,
3684
model->last_trans->cuboid[0][0],
3685
/* the slope function callback is typecast accordingly */
3686
(slope_fn_ptr) slope_fn_grid);
3687
new_h = MIN(new_h, time_elapsed-t-h);
3688
3689
#if VERBOSE > 1
3690
rk4_calls++;
3691
#endif
3692
}
3693
3694
#if VERBOSE > 1
3695
fprintf(stdout, "no. of rk4 calls during compute_temp: %d\n", rk4_calls+1);
3696
#endif
3697
3698
#endif
3699
3700
/* map the temperature numbers back */
3701
xlate_temp_g2b(model, model->last_temp, model->last_trans);
3702
3703
free_grid_model_vector(p);
3704
}
3705
3706
/* debug print */
3707
void debug_print_blist(blist_t *head, flp_t *flp)
3708
{
3709
blist_t *ptr;
3710
fprintf(stdout, "printing blist information...\n");
3711
for(ptr = head; ptr; ptr = ptr->next) {
3712
fprintf(stdout, "unit: %s\n", flp->units[ptr->idx].name);
3713
fprintf(stdout, "occupancy: %f\n", ptr->occupancy);
3714
}
3715
}
3716
3717
void debug_print_glist(glist_t *array, flp_t *flp)
3718
{
3719
int i;
3720
fprintf(stdout, "printing glist information...\n");
3721
for(i=0; i < flp->n_units; i++)
3722
fprintf(stdout, "unit: %s\tstartx: %d\tendx: %d\tstarty: %d\tendy: %d\n",
3723
flp->units[i].name, array[i].j1, array[i].j2, array[i].i1, array[i].i2);
3724
}
3725
3726
void debug_print_layer(grid_model_t *model, layer_t *layer)
3727
{
3728
int i, j;
3729
fprintf(stdout, "printing layer information...\n");
3730
fprintf(stdout, "no: %d\n", layer->no);
3731
fprintf(stdout, "has_lateral: %d\n", layer->has_lateral);
3732
fprintf(stdout, "has_power: %d\n", layer->has_power);
3733
fprintf(stdout, "k: %f\n", layer->k);
3734
fprintf(stdout, "thickness: %f\n", layer->thickness);
3735
fprintf(stdout, "sp: %f\n", layer->sp);
3736
fprintf(stdout, "rx: %f\try: %f\trz: %f\tc: %f\n",
3737
layer->rx, layer->ry, layer->rz, layer->c);
3738
3739
fprintf(stdout, "printing b2gmap information...\n");
3740
for(i=0; i < model->rows; i++)
3741
for(j=0; j < model->cols; j++) {
3742
fprintf(stdout, "row: %d, col: %d\n", i, j);
3743
debug_print_blist(layer->b2gmap[i][j], layer->flp);
3744
}
3745
3746
fprintf(stdout, "printing g2bmap information...\n");
3747
debug_print_glist(layer->g2bmap, layer->flp);
3748
}
3749
3750
//BU_3D added test_b2gmap function
3751
/* test the block-grid map data structure */
3752
void test_b2gmap(grid_model_t *model, layer_t *layer)
3753
{
3754
int i, j;
3755
blist_t *ptr;
3756
double sum;
3757
3758
/* a correctly formed b2gmap should have the
3759
* sum of occupancies in each linked list
3760
* to be equal to 1.0
3761
*/
3762
for (i=0; i < model->rows; i++)
3763
for(j=0; j < model->cols; j++) {
3764
sum = 0.0;
3765
for(ptr = layer->b2gmap[i][j]; ptr; ptr = ptr->next)
3766
sum += ptr->occupancy;
3767
if (!eq(floor(sum*1e5 + 0.5)/1e5, 1.0)) {
3768
fprintf(stdout, "i: %d\tj: %d\n", i, j);
3769
debug_print_blist(layer->b2gmap[i][j], layer->flp);
3770
fatal("erroneous b2gmap data structure. invalid floorplan?\n");
3771
}
3772
}
3773
}//end->BU_3D
3774
3775
void debug_print_grid_model_vector(grid_model_t *model, grid_model_vector_t *v, int nl, int nr, int nc)
3776
{
3777
int n;
3778
int extra_nodes;
3779
3780
if (model->config.model_secondary)
3781
extra_nodes = EXTRA + EXTRA_SEC;
3782
else
3783
extra_nodes = EXTRA;
3784
3785
fprintf(stdout, "printing cuboid information...\n");
3786
for(n=0; n < nl; n++)
3787
dump_dmatrix(v->cuboid[n], nr, nc);
3788
fprintf(stdout, "printing extra information...\n");
3789
dump_dvector(v->extra, extra_nodes);
3790
}
3791
3792
void debug_print_grid(grid_model_t *model)
3793
{
3794
int i;
3795
int extra_nodes;
3796
3797
if (model->config.model_secondary)
3798
extra_nodes = EXTRA + EXTRA_SEC;
3799
else
3800
extra_nodes = EXTRA;
3801
3802
fprintf(stdout, "printing grid model information...\n");
3803
fprintf(stdout, "rows: %d\n", model->rows);
3804
fprintf(stdout, "cols: %d\n", model->cols);
3805
fprintf(stdout, "width: %f\n", model->width);
3806
fprintf(stdout, "height: %f\n", model->height);
3807
3808
debug_print_package_RC(&model->pack);
3809
3810
fprintf(stdout, "total_n_blocks: %d\n", model->total_n_blocks);
3811
fprintf(stdout, "map_mode: %d\n", model->map_mode);
3812
fprintf(stdout, "r_ready: %d\n", model->r_ready);
3813
fprintf(stdout, "c_ready: %d\n", model->c_ready);
3814
fprintf(stdout, "has_lcf: %d\n", model->has_lcf);
3815
3816
fprintf(stdout, "printing last_steady information...\n");
3817
debug_print_grid_model_vector(model, model->last_steady, model->n_layers,
3818
model->rows, model->cols);
3819
3820
fprintf(stdout, "printing last_trans information...\n");
3821
debug_print_grid_model_vector(model, model->last_trans, model->n_layers,
3822
model->rows, model->cols);
3823
3824
fprintf(stdout, "printing last_temp information...\n");
3825
if (model->last_temp)
3826
dump_dvector(model->last_temp, model->total_n_blocks + extra_nodes);
3827
else
3828
fprintf(stdout, "(null)\n");
3829
3830
for(i=0; i < model->n_layers; i++)
3831
debug_print_layer(model, &model->layers[i]);
3832
3833
fprintf(stdout, "base_n_units: %d\n", model->base_n_units);
3834
}
3835
3836
#if SUPERLU > 0
3837
SuperMatrix build_steady_grid_matrix(grid_model_t *model)
3838
{
3839
SuperMatrix A;
3840
double *a;
3841
int *asub, *xa;
3842
double *cooV;
3843
int *cooX, *cooY;
3844
3845
int i, j, l, m, n, nnz;
3846
double dia_val;
3847
int curidx, grididx;
3848
int xoffset, yoffset;
3849
double Rn, Rs, Rw, Re, Ra, Rb;
3850
double R_temp;
3851
3852
/* shortcuts */
3853
int nr = model->rows;
3854
int nc = model->cols;
3855
int nl = model->n_layers;
3856
int spidx, hsidx, subidx, solderidx, pcbidx;
3857
int model_secondary = model->config.model_secondary;
3858
double cw = model->width / model->cols;
3859
double ch = model->height / model->rows;
3860
layer_t *lyr = model->layers;
3861
package_RC_t *pk = &model->pack;
3862
3863
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
3864
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
3865
if(model_secondary){
3866
subidx = LAYER_SUB;
3867
solderidx = LAYER_SOLDER;
3868
pcbidx = LAYER_PCB;
3869
}
3870
3871
/* Initialize matrix A. */
3872
if(model_secondary){
3873
m = n = (nl*nc*nr + EXTRA + EXTRA_SEC);
3874
/* Num of non-zeros
3875
* each layer Five diagonal : c*r, c*(r-1), (c-1)*r, c*(r-1), (c-1)*r
3876
* vertical connections : 2*(nl-1)*nr*nc
3877
* layer peripheral : 5 * 2 * (2*nr+2*nc)
3878
* diaganal for pkg nodes : EXTRA + EXTRA_SEC
3879
* between prim pkg nodes : 2 * 2 * 4
3880
* between sec pkg nodes : 3 * 2 * 4
3881
*/
3882
nnz = 5*nr*nc-2*(nr+nc);
3883
nnz *= nl;
3884
nnz += 2*(nl-1)*nr*nc;
3885
nnz += 5*2*2*(nr+nc);
3886
nnz += EXTRA + EXTRA_SEC;
3887
nnz += 16 + 24;
3888
}
3889
else{
3890
m = n = (nl*nc*nr + EXTRA);
3891
/* Num of non-zeros
3892
* each layer Five diagonal : c*r, c*(r-1), (c-1)*r, c*(r-1), (c-1)*r
3893
* vertical connections : 2*(nl-1)*nr*nc
3894
* sp and hs layer peripheral: 2 * 2 * (2*nr+2*nc)
3895
* diaganal for pkg nodes : EXTRA
3896
* between pkg nodes : 2 * 2 * 4
3897
*/
3898
nnz = 5*nr*nc-2*(nr+nc);
3899
nnz *= nl;
3900
nnz += 2*(nl-1)*nr*nc;
3901
nnz += 2*2*2*(nr+nc);
3902
nnz += EXTRA + 16;
3903
}
3904
3905
if ( !(cooV = doubleMalloc(nnz)) ) fatal("Malloc fails for cooV[].\n");
3906
if ( !(cooX = intMalloc(nnz)) ) fatal("Malloc fails for cooX[].\n");
3907
if ( !(cooY = intMalloc(nnz)) ) fatal("Malloc fails for cooY[].\n");
3908
3909
if ( !(a = doubleMalloc(nnz)) ) fatal("Malloc fails for a[].\n");
3910
if ( !(asub = intMalloc(nnz)) ) fatal("Malloc fails for asub[].\n");
3911
if ( !(xa = intMalloc(n+1)) ) fatal("Malloc fails for xa[].\n");
3912
3913
curidx = 0;
3914
for(l=0; l<nl; l++){
3915
xoffset = l*nr*nc;
3916
yoffset = l*nr*nc;
3917
for(i=0; i<nr; i++){
3918
for(j=0; j<nc; j++){
3919
grididx = i*nc + j;
3920
3921
if(model->config.detailed_3D_used == 1){
3922
if(j > 0) Rw = find_res_3D(l,i,j-1,model,1); else Rw = LARGENUM;
3923
if(j < nc-1) Re = find_res_3D(l,i,j+1,model,1); else Re = LARGENUM;
3924
if(i > 0) Rn = find_res_3D(l,i-1,j,model,2); else Rn = LARGENUM;
3925
if(i < nr-1) Rs = find_res_3D(l,i+1,j,model,2); else Rs = LARGENUM;
3926
if(l > 0) Ra = find_res_3D(l-1,i,j,model,3); else Ra = LARGENUM;
3927
if(l < nl-1) Rb = find_res_3D(l+1,i,j,model,3); else Rb = LARGENUM;
3928
}
3929
else{
3930
if(j > 0) Rw = lyr[l].rx; else Rw = LARGENUM;
3931
if(j < nc-1) Re = lyr[l].rx; else Re = LARGENUM;
3932
if(i > 0) Rn = lyr[l].ry; else Rn = LARGENUM;
3933
if(i < nr-1) Rs = lyr[l].ry; else Rs = LARGENUM;
3934
if(l > 0) Ra = lyr[l-1].rz; else Ra = LARGENUM;
3935
if(l < nl-1) Rb = lyr[l+1].rz; else Rb = LARGENUM;
3936
}
3937
3938
dia_val = 0;
3939
if(0 == grididx){//top left corner
3940
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
3941
cooV[curidx] = -1.0/Re; curidx++; dia_val += 1.0/Re;
3942
3943
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
3944
cooV[curidx] = -1.0/Rs; curidx++; dia_val += 1.0/Rs;
3945
3946
if(l<nl-1){
3947
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
3948
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
3949
}
3950
if(l>0){
3951
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
3952
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
3953
}
3954
3955
if(l == spidx){
3956
/* northern boundary - edge cell has half the ry */
3957
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
3958
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_N;
3959
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3960
/* western boundary - edge cell has half the rx */
3961
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
3962
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_W;
3963
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3964
}
3965
else if(l == hsidx){
3966
/* northern boundary - edge cell has half the ry */
3967
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
3968
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_N;
3969
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3970
/* western boundary - edge cell has half the rx */
3971
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
3972
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_W;
3973
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3974
3975
/* all nodes are connected to the ambient */
3976
R_temp = lyr[l].rz;
3977
dia_val += 1.0/R_temp;
3978
}
3979
else if ((l==subidx) && model_secondary) {
3980
/* northern boundary - edge cell has half the ry */
3981
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
3982
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_N;
3983
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3984
/* western boundary - edge cell has half the rx */
3985
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
3986
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_W;
3987
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3988
}
3989
else if ((l==solderidx) && model_secondary) {
3990
/* northern boundary - edge cell has half the ry */
3991
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
3992
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_N;
3993
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3994
/* western boundary - edge cell has half the rx */
3995
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
3996
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_W;
3997
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
3998
}
3999
else if ((l==pcbidx) && model_secondary) {
4000
/* northern boundary - edge cell has half the ry */
4001
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
4002
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_N;
4003
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4004
/* western boundary - edge cell has half the rx */
4005
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
4006
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_W;
4007
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4008
4009
/* all nodes are connected to the ambient */
4010
R_temp = model->config.r_convec_sec * \
4011
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4012
dia_val += 1.0/R_temp;
4013
}
4014
4015
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4016
cooV[curidx] = dia_val; curidx++;
4017
}
4018
else if((nc-1) == grididx ){//top right corner
4019
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
4020
cooV[curidx] = -1.0/Rw; curidx++; dia_val += 1.0/Rw;
4021
4022
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
4023
cooV[curidx] = -1.0/Rs; curidx++; dia_val += 1.0/Rs;
4024
4025
if(l<nl-1){
4026
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4027
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4028
}
4029
if(l>0){
4030
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4031
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4032
}
4033
4034
if(l == spidx){
4035
/* northern boundary - edge cell has half the ry */
4036
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
4037
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_N;
4038
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4039
/* eastern boundary - edge cell has half the rx */
4040
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
4041
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_E;
4042
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4043
}
4044
else if(l == hsidx){
4045
/* northern boundary - edge cell has half the ry */
4046
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
4047
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_N;
4048
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4049
/* eastern boundary - edge cell has half the rx */
4050
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
4051
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_E;
4052
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4053
4054
/* all nodes are connected to the ambient */
4055
R_temp = lyr[l].rz;
4056
dia_val += 1.0/R_temp;
4057
}
4058
else if ((l==subidx) && model_secondary) {
4059
/* northern boundary - edge cell has half the ry */
4060
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
4061
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_N;
4062
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4063
/* eastern boundary - edge cell has half the rx */
4064
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
4065
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_E;
4066
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4067
}
4068
else if ((l==solderidx) && model_secondary) {
4069
/* northern boundary - edge cell has half the ry */
4070
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
4071
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_N;
4072
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4073
/* eastern boundary - edge cell has half the rx */
4074
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
4075
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_E;
4076
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4077
}
4078
else if ((l==pcbidx) && model_secondary) {
4079
/* northern boundary - edge cell has half the ry */
4080
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
4081
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_N;
4082
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4083
/* eastern boundary - edge cell has half the rx */
4084
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
4085
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_E;
4086
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4087
4088
/* all nodes are connected to the ambient */
4089
R_temp = model->config.r_convec_sec * \
4090
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4091
dia_val += 1.0/R_temp;
4092
}
4093
4094
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4095
cooV[curidx] = dia_val; curidx++;
4096
}
4097
else if((nr*nc-nc) == grididx){//bottom left corner
4098
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
4099
cooV[curidx] = -1.0/Re; curidx++; dia_val += 1.0/Re;
4100
4101
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
4102
cooV[curidx] = -1.0/Rn; curidx++; dia_val += 1.0/Rn;
4103
4104
if(l<nl-1){
4105
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4106
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4107
}
4108
if(l>0){
4109
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4110
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4111
}
4112
4113
if(l == spidx){
4114
/* southern boundary - edge cell has half the ry */
4115
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
4116
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_S;
4117
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4118
/* western boundary - edge cell has half the rx */
4119
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
4120
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_W;
4121
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4122
}
4123
else if(l == hsidx){
4124
/* southern boundary - edge cell has half the ry */
4125
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
4126
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_S;
4127
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4128
/* western boundary - edge cell has half the rx */
4129
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
4130
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_W;
4131
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4132
4133
/* all nodes are connected to the ambient */
4134
R_temp = lyr[l].rz;
4135
dia_val += 1.0/R_temp;
4136
}
4137
else if ((l==subidx) && model_secondary) {
4138
/* southern boundary - edge cell has half the ry */
4139
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
4140
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_S;
4141
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4142
/* western boundary - edge cell has half the rx */
4143
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
4144
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_W;
4145
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4146
}
4147
else if ((l==solderidx) && model_secondary) {
4148
/* southern boundary - edge cell has half the ry */
4149
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
4150
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_S;
4151
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4152
/* western boundary - edge cell has half the rx */
4153
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
4154
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_W;
4155
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4156
}
4157
else if ((l==pcbidx) && model_secondary) {
4158
/* southern boundary - edge cell has half the ry */
4159
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
4160
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_S;
4161
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4162
/* western boundary - edge cell has half the rx */
4163
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
4164
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_W;
4165
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4166
4167
/* all nodes are connected to the ambient */
4168
R_temp = model->config.r_convec_sec * \
4169
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4170
dia_val += 1.0/R_temp;
4171
}
4172
4173
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4174
cooV[curidx] = dia_val; curidx++;
4175
}
4176
else if((nr*nc-1) == grididx){//bottom right corner
4177
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
4178
cooV[curidx] = -1.0/Rw; curidx++; dia_val += 1.0/Rw;
4179
4180
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
4181
cooV[curidx] = -1.0/Rn; curidx++; dia_val += 1.0/Rn;
4182
4183
if(l<nl-1){
4184
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4185
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4186
}
4187
if(l>0){
4188
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4189
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4190
}
4191
4192
if(l == spidx){
4193
/* southern boundary - edge cell has half the ry */
4194
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
4195
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_S;
4196
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4197
/* eastern boundary - edge cell has half the rx */
4198
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
4199
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_E;
4200
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4201
}
4202
else if(l == hsidx){
4203
/* southern boundary - edge cell has half the ry */
4204
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
4205
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_S;
4206
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4207
/* eastern boundary - edge cell has half the rx */
4208
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
4209
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_E;
4210
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4211
4212
/* all nodes are connected to the ambient */
4213
R_temp = lyr[l].rz;
4214
dia_val += 1.0/R_temp;
4215
}
4216
else if ((l==subidx) && model_secondary) {
4217
/* southern boundary - edge cell has half the ry */
4218
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
4219
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_S;
4220
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4221
/* eastern boundary - edge cell has half the rx */
4222
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
4223
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_E;
4224
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4225
}
4226
else if ((l==solderidx) && model_secondary) {
4227
/* southern boundary - edge cell has half the ry */
4228
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
4229
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_S;
4230
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4231
/* eastern boundary - edge cell has half the rx */
4232
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
4233
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_E;
4234
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4235
}
4236
else if ((l==pcbidx) && model_secondary) {
4237
/* southern boundary - edge cell has half the ry */
4238
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
4239
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_S;
4240
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4241
/* eastern boundary - edge cell has half the rx */
4242
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
4243
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_E;
4244
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4245
4246
/* all nodes are connected to the ambient */
4247
R_temp = model->config.r_convec_sec * \
4248
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4249
dia_val += 1.0/R_temp;
4250
}
4251
4252
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4253
cooV[curidx] = dia_val; curidx++;
4254
}
4255
else if((grididx > 0) && (grididx < nc-1)){//top row
4256
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
4257
cooV[curidx] = -1.0/Rw; curidx++; dia_val += 1.0/Rw;
4258
4259
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
4260
cooV[curidx] = -1.0/Re; curidx++; dia_val += 1.0/Re;
4261
4262
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
4263
cooV[curidx] = -1.0/Rs; curidx++; dia_val += 1.0/Rs;
4264
4265
if(l<nl-1){
4266
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4267
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4268
}
4269
if(l>0){
4270
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4271
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4272
}
4273
4274
if(l == spidx){
4275
/* northern boundary - edge cell has half the ry */
4276
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
4277
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_N;
4278
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4279
}
4280
else if(l == hsidx){
4281
/* northern boundary - edge cell has half the ry */
4282
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
4283
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_N;
4284
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4285
4286
/* all nodes are connected to the ambient */
4287
R_temp = lyr[l].rz;
4288
dia_val += 1.0/R_temp;
4289
}
4290
else if ((l==subidx) && model_secondary) {
4291
/* northern boundary - edge cell has half the ry */
4292
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
4293
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_N;
4294
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4295
}
4296
else if ((l==solderidx) && model_secondary) {
4297
/* northern boundary - edge cell has half the ry */
4298
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
4299
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_N;
4300
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4301
}
4302
else if ((l==pcbidx) && model_secondary) {
4303
/* northern boundary - edge cell has half the ry */
4304
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
4305
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_N;
4306
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4307
4308
/* all nodes are connected to the ambient */
4309
R_temp = model->config.r_convec_sec * \
4310
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4311
dia_val += 1.0/R_temp;
4312
}
4313
4314
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4315
cooV[curidx] = dia_val; curidx++;
4316
}
4317
else if((grididx > nr*nc-nc) && (grididx < nr*nc-1)){//bottom row
4318
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
4319
cooV[curidx] = -1.0/Rw; curidx++; dia_val += 1.0/Rw;
4320
4321
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
4322
cooV[curidx] = -1.0/Re; curidx++; dia_val += 1.0/Re;
4323
4324
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
4325
cooV[curidx] = -1.0/Rn; curidx++; dia_val += 1.0/Rn;
4326
4327
if(l<nl-1){
4328
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4329
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4330
}
4331
if(l>0){
4332
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4333
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4334
}
4335
4336
if(l == spidx){
4337
/* southern boundary - edge cell has half the ry */
4338
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
4339
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_S;
4340
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4341
}
4342
else if(l == hsidx){
4343
/* southern boundary - edge cell has half the ry */
4344
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
4345
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_S;
4346
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4347
4348
/* all nodes are connected to the ambient */
4349
R_temp = lyr[l].rz;
4350
dia_val += 1.0/R_temp;
4351
}
4352
else if ((l==subidx) && model_secondary) {
4353
/* southern boundary - edge cell has half the ry */
4354
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
4355
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_S;
4356
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4357
}
4358
else if ((l==solderidx) && model_secondary) {
4359
/* southern boundary - edge cell has half the ry */
4360
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
4361
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_S;
4362
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4363
}
4364
else if ((l==pcbidx) && model_secondary) {
4365
/* southern boundary - edge cell has half the ry */
4366
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
4367
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_S;
4368
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4369
4370
/* all nodes are connected to the ambient */
4371
R_temp = model->config.r_convec_sec * \
4372
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4373
dia_val += 1.0/R_temp;
4374
}
4375
4376
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4377
cooV[curidx] = dia_val; curidx++;
4378
}
4379
else if(0 == (grididx%nc)){//leftmost column
4380
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
4381
cooV[curidx] = -1.0/Rn; curidx++; dia_val += 1.0/Rn;
4382
4383
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
4384
cooV[curidx] = -1.0/Rs; curidx++; dia_val += 1.0/Rs;
4385
4386
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
4387
cooV[curidx] = -1.0/Re; curidx++; dia_val += 1.0/Re;
4388
4389
if(l<nl-1){
4390
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4391
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4392
}
4393
if(l>0){
4394
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4395
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4396
}
4397
4398
if(l == spidx){
4399
/* western boundary - edge cell has half the rx */
4400
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
4401
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_W;
4402
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4403
}
4404
else if(l == hsidx){
4405
/* western boundary - edge cell has half the rx */
4406
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
4407
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_W;
4408
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4409
4410
/* all nodes are connected to the ambient */
4411
R_temp = lyr[l].rz;
4412
dia_val += 1.0/R_temp;
4413
}
4414
else if ((l==subidx) && model_secondary) {
4415
/* western boundary - edge cell has half the rx */
4416
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
4417
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_W;
4418
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4419
}
4420
else if ((l==solderidx) && model_secondary) {
4421
/* western boundary - edge cell has half the rx */
4422
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
4423
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_W;
4424
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4425
}
4426
else if ((l==pcbidx) && model_secondary) {
4427
/* western boundary - edge cell has half the rx */
4428
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
4429
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_W;
4430
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4431
4432
/* all nodes are connected to the ambient */
4433
R_temp = model->config.r_convec_sec * \
4434
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4435
dia_val += 1.0/R_temp;
4436
}
4437
4438
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4439
cooV[curidx] = dia_val; curidx++;
4440
}
4441
else if(0 == ((grididx+1)%nc)){//rightmost column
4442
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
4443
cooV[curidx] = -1.0/Rn; curidx++; dia_val += 1.0/Rn;
4444
4445
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
4446
cooV[curidx] = -1.0/Rs; curidx++; dia_val += 1.0/Rs;
4447
4448
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
4449
cooV[curidx] = -1.0/Rw; curidx++; dia_val += 1.0/Rw;
4450
4451
if(l<nl-1){
4452
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4453
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4454
}
4455
if(l>0){
4456
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4457
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4458
}
4459
4460
if(l == spidx){
4461
/* eastern boundary - edge cell has half the rx */
4462
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
4463
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_E;
4464
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4465
}
4466
else if(l == hsidx){
4467
/* eastern boundary - edge cell has half the rx */
4468
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
4469
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_E;
4470
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4471
4472
/* all nodes are connected to the ambient */
4473
R_temp = lyr[l].rz;
4474
dia_val += 1.0/R_temp;
4475
}
4476
else if ((l==subidx) && model_secondary) {
4477
/* eastern boundary - edge cell has half the rx */
4478
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
4479
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_E;
4480
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4481
}
4482
else if ((l==solderidx) && model_secondary) {
4483
/* eastern boundary - edge cell has half the rx */
4484
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
4485
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_E;
4486
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4487
}
4488
else if ((l==pcbidx) && model_secondary) {
4489
/* eastern boundary - edge cell has half the rx */
4490
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
4491
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_E;
4492
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4493
4494
/* all nodes are connected to the ambient */
4495
R_temp = model->config.r_convec_sec * \
4496
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4497
dia_val += 1.0/R_temp;
4498
}
4499
4500
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4501
cooV[curidx] = dia_val; curidx++;
4502
}
4503
else{//central grid cell
4504
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
4505
cooV[curidx] = -1.0/Rn; curidx++; dia_val += 1.0/Rn;
4506
4507
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
4508
cooV[curidx] = -1.0/Rs; curidx++; dia_val += 1.0/Rs;
4509
4510
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
4511
cooV[curidx] = -1.0/Rw; curidx++; dia_val += 1.0/Rw;
4512
4513
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
4514
cooV[curidx] = -1.0/Re; curidx++; dia_val += 1.0/Re;
4515
4516
if(l<nl-1){
4517
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
4518
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
4519
}
4520
if(l>0){
4521
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
4522
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
4523
}
4524
4525
if(l == hsidx){
4526
/* all nodes are connected to the ambient */
4527
R_temp = lyr[l].rz;
4528
dia_val += 1.0/R_temp;
4529
}
4530
else if ((l==pcbidx) && model_secondary) {
4531
/* all nodes are connected to the ambient */
4532
R_temp = model->config.r_convec_sec * \
4533
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
4534
dia_val += 1.0/R_temp;
4535
}
4536
4537
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
4538
cooV[curidx] = dia_val; curidx++;
4539
}
4540
}
4541
}
4542
}
4543
4544
/* Package nodes */
4545
/* sink outer north/south */
4546
xoffset = nl*nr*nc;
4547
yoffset = nl*nr*nc;
4548
dia_val = 0;
4549
R_temp = pk->r_hs2_y + pk->r_hs;
4550
cooX[curidx] = SINK_N+xoffset; cooY[curidx] = SINK_C_N+yoffset;
4551
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4552
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
4553
cooX[curidx] = SINK_N+xoffset; cooY[curidx] = SINK_N+yoffset;
4554
cooV[curidx] = dia_val; curidx++;
4555
4556
dia_val = 0;
4557
R_temp = pk->r_hs2_y + pk->r_hs;
4558
cooX[curidx] = SINK_S+xoffset; cooY[curidx] = SINK_C_S+yoffset;
4559
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4560
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
4561
cooX[curidx] = SINK_S+xoffset; cooY[curidx] = SINK_S+yoffset;
4562
cooV[curidx] = dia_val; curidx++;
4563
4564
/* sink outer west/east */
4565
dia_val = 0;
4566
R_temp = pk->r_hs2_x + pk->r_hs;
4567
cooX[curidx] = SINK_W+xoffset; cooY[curidx] = SINK_C_W+yoffset;
4568
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4569
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
4570
cooX[curidx] = SINK_W+xoffset; cooY[curidx] = SINK_W+yoffset;
4571
cooV[curidx] = dia_val; curidx++;
4572
4573
dia_val = 0;
4574
R_temp = pk->r_hs2_x + pk->r_hs;
4575
cooX[curidx] = SINK_E+xoffset; cooY[curidx] = SINK_C_E+yoffset;
4576
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4577
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
4578
cooX[curidx] = SINK_E+xoffset; cooY[curidx] = SINK_E+yoffset;
4579
cooV[curidx] = dia_val; curidx++;
4580
4581
/* sink inner north/south */
4582
xoffset = nl*nr*nc;
4583
yoffset = hsidx*nr*nc;
4584
dia_val = 0;
4585
for(i=0, j=0; j < nc; j++){
4586
grididx = i*nc + j;
4587
R_temp = lyr[hsidx].ry / 2.0 + nc * pk->r_hs1_y;
4588
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = grididx+yoffset;
4589
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4590
}
4591
xoffset = nl*nr*nc;
4592
yoffset = nl*nr*nc;
4593
R_temp = pk->r_sp_per_y;
4594
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = SP_N+yoffset;
4595
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4596
R_temp = pk->r_hs2_y + pk->r_hs;
4597
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = SINK_N+yoffset;
4598
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4599
R_temp = pk->r_hs_c_per_y + pk->r_amb_c_per_y; dia_val += 1.0/R_temp;
4600
4601
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = SINK_C_N+yoffset;
4602
cooV[curidx] = dia_val; curidx++;
4603
4604
xoffset = nl*nr*nc;
4605
yoffset = hsidx*nr*nc;
4606
dia_val = 0;
4607
for(i=nr-1, j=0; j < nc; j++){
4608
grididx = i*nc + j;
4609
R_temp = lyr[hsidx].ry / 2.0 + nc * pk->r_hs1_y;
4610
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = grididx+yoffset;
4611
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4612
}
4613
xoffset = nl*nr*nc;
4614
yoffset = nl*nr*nc;
4615
R_temp = pk->r_sp_per_y;
4616
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = SP_S+yoffset;
4617
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4618
R_temp = pk->r_hs2_y + pk->r_hs;
4619
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = SINK_S+yoffset;
4620
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4621
R_temp = pk->r_hs_c_per_y + pk->r_amb_c_per_y; dia_val += 1.0/R_temp;
4622
4623
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = SINK_C_S+yoffset;
4624
cooV[curidx] = dia_val; curidx++;
4625
4626
/* sink inner west/east */
4627
xoffset = nl*nr*nc;
4628
yoffset = hsidx*nr*nc;
4629
dia_val = 0;
4630
for(i=0, j=0; i < nr; i++){
4631
grididx = i*nc + j;
4632
R_temp = lyr[hsidx].rx / 2.0 + nr * pk->r_hs1_x;
4633
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = grididx+yoffset;
4634
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4635
}
4636
xoffset = nl*nr*nc;
4637
yoffset = nl*nr*nc;
4638
R_temp = pk->r_sp_per_x;
4639
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = SP_W+yoffset;
4640
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4641
R_temp = pk->r_hs2_x + pk->r_hs;
4642
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = SINK_W+yoffset;
4643
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4644
R_temp = pk->r_hs_c_per_x + pk->r_amb_c_per_x; dia_val += 1.0/R_temp;
4645
4646
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = SINK_C_W+yoffset;
4647
cooV[curidx] = dia_val; curidx++;
4648
4649
xoffset = nl*nr*nc;
4650
yoffset = hsidx*nr*nc;
4651
dia_val = 0;
4652
for(i=0, j=nc-1; i < nr; i++){
4653
grididx = i*nc + j;
4654
R_temp = lyr[hsidx].rx / 2.0 + nr * pk->r_hs1_x;
4655
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = grididx+yoffset;
4656
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4657
}
4658
xoffset = nl*nr*nc;
4659
yoffset = nl*nr*nc;
4660
R_temp = pk->r_sp_per_x;
4661
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = SP_E+yoffset;
4662
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4663
R_temp = pk->r_hs2_x + pk->r_hs;
4664
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = SINK_E+yoffset;
4665
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4666
R_temp = pk->r_hs_c_per_x + pk->r_amb_c_per_x; dia_val += 1.0/R_temp;
4667
4668
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = SINK_C_E+yoffset;
4669
cooV[curidx] = dia_val; curidx++;
4670
4671
/* spreader north/south */
4672
xoffset = nl*nr*nc;
4673
yoffset = spidx*nr*nc;
4674
dia_val = 0;
4675
for(i=0, j=0; j < nc; j++){
4676
grididx = i*nc + j;
4677
R_temp = lyr[spidx].ry / 2.0 + nc * pk->r_sp1_y;
4678
cooX[curidx] = SP_N+xoffset; cooY[curidx] = grididx+yoffset;
4679
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4680
}
4681
xoffset = nl*nr*nc;
4682
yoffset = nl*nr*nc;
4683
R_temp = pk->r_sp_per_y;
4684
cooX[curidx] = SP_N+xoffset; cooY[curidx] = SINK_C_N+yoffset;
4685
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4686
4687
cooX[curidx] = SP_N+xoffset; cooY[curidx] = SP_N+yoffset;
4688
cooV[curidx] = dia_val; curidx++;
4689
4690
xoffset = nl*nr*nc;
4691
yoffset = spidx*nr*nc;
4692
dia_val = 0;
4693
for(i=nr-1, j=0; j < nc; j++){
4694
grididx = i*nc + j;
4695
R_temp = lyr[spidx].ry / 2.0 + nc * pk->r_sp1_y;
4696
cooX[curidx] = SP_S+xoffset; cooY[curidx] = grididx+yoffset;
4697
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4698
}
4699
xoffset = nl*nr*nc;
4700
yoffset = nl*nr*nc;
4701
R_temp = pk->r_sp_per_y;
4702
cooX[curidx] = SP_S+xoffset; cooY[curidx] = SINK_C_S+yoffset;
4703
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4704
4705
cooX[curidx] = SP_S+xoffset; cooY[curidx] = SP_S+yoffset;
4706
cooV[curidx] = dia_val; curidx++;
4707
4708
/* spreader west/east */
4709
xoffset = nl*nr*nc;
4710
yoffset = spidx*nr*nc;
4711
dia_val = 0;
4712
for(i=0, j=0; i < nr; i++){
4713
grididx = i*nc + j;
4714
R_temp = lyr[spidx].rx / 2.0 + nr * pk->r_sp1_x;
4715
cooX[curidx] = SP_W+xoffset; cooY[curidx] = grididx+yoffset;
4716
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4717
}
4718
xoffset = nl*nr*nc;
4719
yoffset = nl*nr*nc;
4720
R_temp = pk->r_sp_per_x;
4721
cooX[curidx] = SP_W+xoffset; cooY[curidx] = SINK_C_W+yoffset;
4722
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4723
4724
cooX[curidx] = SP_W+xoffset; cooY[curidx] = SP_W+yoffset;
4725
cooV[curidx] = dia_val; curidx++;
4726
4727
xoffset = nl*nr*nc;
4728
yoffset = spidx*nr*nc;
4729
dia_val = 0;
4730
for(i=0, j=nc-1; i < nr; i++){
4731
grididx = i*nc + j;
4732
R_temp = lyr[spidx].rx / 2.0 + nr * pk->r_sp1_x;
4733
cooX[curidx] = SP_E+xoffset; cooY[curidx] = grididx+yoffset;
4734
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4735
}
4736
xoffset = nl*nr*nc;
4737
yoffset = nl*nr*nc;
4738
R_temp = pk->r_sp_per_x;
4739
cooX[curidx] = SP_E+xoffset; cooY[curidx] = SINK_C_E+yoffset;
4740
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4741
4742
cooX[curidx] = SP_E+xoffset; cooY[curidx] = SP_E+yoffset;
4743
cooV[curidx] = dia_val; curidx++;
4744
4745
if(model_secondary){
4746
/* secondary path package nodes */
4747
/* PCB outer north/south */
4748
xoffset = nl*nr*nc;
4749
yoffset = nl*nr*nc;
4750
dia_val = 0;
4751
R_temp = pk->r_pcb2_y + pk->r_pcb;
4752
cooX[curidx] = PCB_N+xoffset; cooY[curidx] = PCB_C_N+yoffset;
4753
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4754
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
4755
cooX[curidx] = PCB_N+xoffset; cooY[curidx] = PCB_N+yoffset;
4756
cooV[curidx] = dia_val; curidx++;
4757
4758
dia_val = 0;
4759
R_temp = pk->r_pcb2_y + pk->r_pcb;
4760
cooX[curidx] = PCB_S+xoffset; cooY[curidx] = PCB_C_S+yoffset;
4761
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4762
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
4763
cooX[curidx] = PCB_S+xoffset; cooY[curidx] = PCB_S+yoffset;
4764
cooV[curidx] = dia_val; curidx++;
4765
4766
/* PCB outer west/east */
4767
dia_val = 0;
4768
R_temp = pk->r_pcb2_x + pk->r_pcb;
4769
cooX[curidx] = PCB_W+xoffset; cooY[curidx] = PCB_C_W+yoffset;
4770
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4771
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
4772
cooX[curidx] = PCB_W+xoffset; cooY[curidx] = PCB_W+yoffset;
4773
cooV[curidx] = dia_val; curidx++;
4774
4775
dia_val = 0;
4776
R_temp = pk->r_pcb2_x + pk->r_pcb;
4777
cooX[curidx] = PCB_E+xoffset; cooY[curidx] = PCB_C_E+yoffset;
4778
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4779
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
4780
cooX[curidx] = PCB_E+xoffset; cooY[curidx] = PCB_E+yoffset;
4781
cooV[curidx] = dia_val; curidx++;
4782
4783
/* PCB inner north/south */
4784
xoffset = nl*nr*nc;
4785
yoffset = pcbidx*nr*nc;
4786
dia_val = 0;
4787
for(i=0, j=0; j < nc; j++){
4788
grididx = i*nc + j;
4789
R_temp = lyr[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y;
4790
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = grididx+yoffset;
4791
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4792
}
4793
xoffset = nl*nr*nc;
4794
yoffset = nl*nr*nc;
4795
R_temp = pk->r_pcb_c_per_y;
4796
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = SOLDER_N+yoffset;
4797
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4798
R_temp = pk->r_pcb2_y + pk->r_pcb;
4799
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = PCB_N+yoffset;
4800
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4801
R_temp = pk->r_amb_sec_c_per_y; dia_val += 1.0/R_temp;
4802
4803
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = PCB_C_N+yoffset;
4804
cooV[curidx] = dia_val; curidx++;
4805
4806
xoffset = nl*nr*nc;
4807
yoffset = pcbidx*nr*nc;
4808
dia_val = 0;
4809
for(i=nr-1, j=0; j < nc; j++){
4810
grididx = i*nc + j;
4811
R_temp = lyr[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y;
4812
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = grididx+yoffset;
4813
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4814
}
4815
xoffset = nl*nr*nc;
4816
yoffset = nl*nr*nc;
4817
R_temp = pk->r_pcb_c_per_y;
4818
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = SOLDER_S+yoffset;
4819
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4820
R_temp = pk->r_pcb2_y + pk->r_pcb;
4821
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = PCB_S+yoffset;
4822
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4823
R_temp = pk->r_amb_sec_c_per_y; dia_val += 1.0/R_temp;
4824
4825
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = PCB_C_S+yoffset;
4826
cooV[curidx] = dia_val; curidx++;
4827
4828
/* PCB inner west/east */
4829
xoffset = nl*nr*nc;
4830
yoffset = pcbidx*nr*nc;
4831
dia_val = 0;
4832
for(i=0, j=0; i < nr; i++){
4833
grididx = i*nc + j;
4834
R_temp = lyr[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x;
4835
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = grididx+yoffset;
4836
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4837
}
4838
xoffset = nl*nr*nc;
4839
yoffset = nl*nr*nc;
4840
R_temp = pk->r_pcb_c_per_x;
4841
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = SOLDER_W+yoffset;
4842
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4843
R_temp = pk->r_pcb2_x + pk->r_pcb;
4844
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = PCB_W+yoffset;
4845
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4846
R_temp = pk->r_amb_sec_c_per_x; dia_val += 1.0/R_temp;
4847
4848
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = PCB_C_W+yoffset;
4849
cooV[curidx] = dia_val; curidx++;
4850
4851
xoffset = nl*nr*nc;
4852
yoffset = pcbidx*nr*nc;
4853
dia_val = 0;
4854
for(i=0, j=nc-1; i < nr; i++){
4855
grididx = i*nc + j;
4856
R_temp = lyr[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x;
4857
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = grididx+yoffset;
4858
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4859
}
4860
xoffset = nl*nr*nc;
4861
yoffset = nl*nr*nc;
4862
R_temp = pk->r_pcb_c_per_x;
4863
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = SOLDER_E+yoffset;
4864
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4865
R_temp = pk->r_pcb2_x + pk->r_pcb;
4866
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = PCB_E+yoffset;
4867
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4868
R_temp = pk->r_amb_sec_c_per_x; dia_val += 1.0/R_temp;
4869
4870
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = PCB_C_E+yoffset;
4871
cooV[curidx] = dia_val; curidx++;
4872
4873
/* solder north/south */
4874
xoffset = nl*nr*nc;
4875
yoffset = solderidx*nr*nc;
4876
dia_val = 0;
4877
for(i=0, j=0; j < nc; j++){
4878
grididx = i*nc + j;
4879
R_temp = lyr[solderidx].ry / 2.0 + nc * pk->r_solder1_y;
4880
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = grididx+yoffset;
4881
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4882
}
4883
xoffset = nl*nr*nc;
4884
yoffset = nl*nr*nc;
4885
R_temp = pk->r_solder_per_y;
4886
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = SUB_N+yoffset;
4887
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4888
R_temp = pk->r_pcb_c_per_y;
4889
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = PCB_C_N+yoffset;
4890
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4891
4892
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = SOLDER_N+yoffset;
4893
cooV[curidx] = dia_val; curidx++;
4894
4895
xoffset = nl*nr*nc;
4896
yoffset = solderidx*nr*nc;
4897
dia_val = 0;
4898
for(i=nr-1, j=0; j < nc; j++){
4899
grididx = i*nc + j;
4900
R_temp = lyr[solderidx].ry / 2.0 + nc * pk->r_solder1_y;
4901
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = grididx+yoffset;
4902
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4903
}
4904
xoffset = nl*nr*nc;
4905
yoffset = nl*nr*nc;
4906
R_temp = pk->r_solder_per_y;
4907
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = SUB_S+yoffset;
4908
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4909
R_temp = pk->r_pcb_c_per_y;
4910
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = PCB_C_S+yoffset;
4911
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4912
4913
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = SOLDER_S+yoffset;
4914
cooV[curidx] = dia_val; curidx++;
4915
4916
/* solder west/east */
4917
xoffset = nl*nr*nc;
4918
yoffset = solderidx*nr*nc;
4919
dia_val = 0;
4920
for(i=0, j=0; i < nr; i++){
4921
grididx = i*nc + j;
4922
R_temp = lyr[solderidx].rx / 2.0 + nr * pk->r_solder1_x;
4923
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = grididx+yoffset;
4924
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4925
}
4926
xoffset = nl*nr*nc;
4927
yoffset = nl*nr*nc;
4928
R_temp = pk->r_solder_per_x;
4929
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = SUB_W+yoffset;
4930
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4931
R_temp = pk->r_pcb_c_per_x;
4932
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = PCB_C_W+yoffset;
4933
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4934
4935
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = SOLDER_W+yoffset;
4936
cooV[curidx] = dia_val; curidx++;
4937
4938
xoffset = nl*nr*nc;
4939
yoffset = solderidx*nr*nc;
4940
dia_val = 0;
4941
for(i=0, j=nc-1; i < nr; i++){
4942
grididx = i*nc + j;
4943
R_temp = lyr[solderidx].rx / 2.0 + nr * pk->r_solder1_x;
4944
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = grididx+yoffset;
4945
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4946
}
4947
xoffset = nl*nr*nc;
4948
yoffset = nl*nr*nc;
4949
R_temp = pk->r_solder_per_x;
4950
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = SUB_E+yoffset;
4951
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4952
R_temp = pk->r_pcb_c_per_x;
4953
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = PCB_C_E+yoffset;
4954
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4955
4956
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = SOLDER_E+yoffset;
4957
cooV[curidx] = dia_val; curidx++;
4958
4959
/* substrate north/south */
4960
xoffset = nl*nr*nc;
4961
yoffset = subidx*nr*nc;
4962
dia_val = 0;
4963
for(i=0, j=0; j < nc; j++){
4964
grididx = i*nc + j;
4965
R_temp = lyr[subidx].ry / 2.0 + nc * pk->r_sub1_y;
4966
cooX[curidx] = SUB_N+xoffset; cooY[curidx] = grididx+yoffset;
4967
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4968
}
4969
xoffset = nl*nr*nc;
4970
yoffset = nl*nr*nc;
4971
R_temp = pk->r_solder_per_y;
4972
cooX[curidx] = SUB_N+xoffset; cooY[curidx] = SOLDER_N+yoffset;
4973
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4974
4975
cooX[curidx] = SUB_N+xoffset; cooY[curidx] = SUB_N+yoffset;
4976
cooV[curidx] = dia_val; curidx++;
4977
4978
xoffset = nl*nr*nc;
4979
yoffset = subidx*nr*nc;
4980
dia_val = 0;
4981
for(i=nr-1, j=0; j < nc; j++){
4982
grididx = i*nc + j;
4983
R_temp = lyr[subidx].ry / 2.0 + nc * pk->r_sub1_y;
4984
cooX[curidx] = SUB_S+xoffset; cooY[curidx] = grididx+yoffset;
4985
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4986
}
4987
xoffset = nl*nr*nc;
4988
yoffset = nl*nr*nc;
4989
R_temp = pk->r_solder_per_y;
4990
cooX[curidx] = SUB_S+xoffset; cooY[curidx] = SOLDER_S+yoffset;
4991
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
4992
4993
cooX[curidx] = SUB_S+xoffset; cooY[curidx] = SUB_S+yoffset;
4994
cooV[curidx] = dia_val; curidx++;
4995
4996
/* substrate west/east */
4997
xoffset = nl*nr*nc;
4998
yoffset = subidx*nr*nc;
4999
dia_val = 0;
5000
for(i=0, j=0; i < nr; i++){
5001
grididx = i*nc + j;
5002
R_temp = lyr[subidx].rx / 2.0 + nr * pk->r_sub1_x;
5003
cooX[curidx] = SUB_W+xoffset; cooY[curidx] = grididx+yoffset;
5004
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5005
}
5006
xoffset = nl*nr*nc;
5007
yoffset = nl*nr*nc;
5008
R_temp = pk->r_solder_per_x;
5009
cooX[curidx] = SUB_W+xoffset; cooY[curidx] = SOLDER_W+yoffset;
5010
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5011
5012
cooX[curidx] = SUB_W+xoffset; cooY[curidx] = SUB_W+yoffset;
5013
cooV[curidx] = dia_val; curidx++;
5014
5015
xoffset = nl*nr*nc;
5016
yoffset = subidx*nr*nc;
5017
dia_val = 0;
5018
for(i=0, j=nc-1; i < nr; i++){
5019
grididx = i*nc + j;
5020
R_temp = lyr[subidx].rx / 2.0 + nr * pk->r_sub1_x;
5021
cooX[curidx] = SUB_E+xoffset; cooY[curidx] = grididx+yoffset;
5022
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5023
}
5024
xoffset = nl*nr*nc;
5025
yoffset = nl*nr*nc;
5026
R_temp = pk->r_solder_per_x;
5027
cooX[curidx] = SUB_E+xoffset; cooY[curidx] = SOLDER_E+yoffset;
5028
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5029
5030
cooX[curidx] = SUB_E+xoffset; cooY[curidx] = SUB_E+yoffset;
5031
cooV[curidx] = dia_val; curidx++;
5032
}
5033
5034
if(curidx != nnz)
5035
fatal("Steady-state Matrix build error: less elements than nnz\n");
5036
5037
coo2csc(n, nnz, cooX, cooY, cooV, asub, xa, a);
5038
5039
/* Create matrix A in the format expected by SuperLU. */
5040
dCreate_CompCol_Matrix(&A, m, n, nnz, a, asub, xa, SLU_NC, SLU_D, SLU_GE);
5041
5042
free(cooV);
5043
free(cooX);
5044
free(cooY);
5045
5046
return A;
5047
}
5048
5049
SuperMatrix build_steady_rhs_vector(grid_model_t *model, grid_model_vector_t *power, double **power_vector)
5050
{
5051
SuperMatrix B;
5052
int idx, npower_vector;
5053
int i, j, l, m;
5054
int base_idx;
5055
5056
/* shortcuts */
5057
int nr = model->rows;
5058
int nc = model->cols;
5059
int nl = model->n_layers;
5060
int hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
5061
int pcbidx = LAYER_PCB;
5062
int model_secondary = model->config.model_secondary;
5063
double cw = model->width / model->cols;
5064
double ch = model->height / model->rows;
5065
thermal_config_t *c = &model->config;
5066
layer_t *lyr = model->layers;
5067
package_RC_t *pk = &model->pack;
5068
5069
if(model_secondary)
5070
m = (nl*nc*nr + EXTRA + EXTRA_SEC);
5071
else
5072
m = (nl*nc*nr + EXTRA);
5073
5074
npower_vector = 1;
5075
if ( !(*power_vector = doubleMalloc(m*npower_vector)) ) fatal("Malloc fails for power_vector[].\n");
5076
5077
for(l=0; l<nl; l++)
5078
for(i=0; i<nr; i++)
5079
for(j=0; j<nc; j++){
5080
idx = l*nr*nc + i*nc + j;
5081
if(l == hsidx){
5082
(*power_vector)[idx] = c->ambient/lyr[l].rz + power->cuboid[l][i][j];
5083
}
5084
else if((l == pcbidx) && model_secondary){
5085
(*power_vector)[idx] = power->cuboid[l][i][j] + c->ambient/(model->config.r_convec_sec *
5086
(model->config.s_pcb * model->config.s_pcb) / (cw * ch));
5087
}
5088
else{
5089
(*power_vector)[idx] = power->cuboid[l][i][j];
5090
}
5091
}
5092
/* Package nodes */
5093
base_idx = nl*nc*nr;
5094
(*power_vector)[base_idx + SP_W] = 0;
5095
(*power_vector)[base_idx + SP_E] = 0;
5096
(*power_vector)[base_idx + SP_N] = 0;
5097
(*power_vector)[base_idx + SP_S] = 0;
5098
(*power_vector)[base_idx + SINK_C_W] = c->ambient/(pk->r_hs_c_per_x + pk->r_amb_c_per_x);
5099
(*power_vector)[base_idx + SINK_C_E] = c->ambient/(pk->r_hs_c_per_x + pk->r_amb_c_per_x);
5100
(*power_vector)[base_idx + SINK_C_N] = c->ambient/(pk->r_hs_c_per_y + pk->r_amb_c_per_y);
5101
(*power_vector)[base_idx + SINK_C_S] = c->ambient/(pk->r_hs_c_per_y + pk->r_amb_c_per_y);
5102
(*power_vector)[base_idx + SINK_W] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
5103
(*power_vector)[base_idx + SINK_E] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
5104
(*power_vector)[base_idx + SINK_N] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
5105
(*power_vector)[base_idx + SINK_S] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
5106
if(model_secondary){
5107
(*power_vector)[base_idx + SUB_W] = 0;
5108
(*power_vector)[base_idx + SUB_E] = 0;
5109
(*power_vector)[base_idx + SUB_N] = 0;
5110
(*power_vector)[base_idx + SUB_S] = 0;
5111
(*power_vector)[base_idx + SOLDER_W] = 0;
5112
(*power_vector)[base_idx + SOLDER_E] = 0;
5113
(*power_vector)[base_idx + SOLDER_N] = 0;
5114
(*power_vector)[base_idx + SOLDER_S] = 0;
5115
(*power_vector)[base_idx + PCB_C_W] = c->ambient/(pk->r_amb_sec_c_per_x);
5116
(*power_vector)[base_idx + PCB_C_E] = c->ambient/(pk->r_amb_sec_c_per_x);
5117
(*power_vector)[base_idx + PCB_C_N] = c->ambient/(pk->r_amb_sec_c_per_y);
5118
(*power_vector)[base_idx + PCB_C_S] = c->ambient/(pk->r_amb_sec_c_per_y);
5119
(*power_vector)[base_idx + PCB_W] = c->ambient/(pk->r_amb_sec_per);
5120
(*power_vector)[base_idx + PCB_E] = c->ambient/(pk->r_amb_sec_per);
5121
(*power_vector)[base_idx + PCB_N] = c->ambient/(pk->r_amb_sec_per);
5122
(*power_vector)[base_idx + PCB_S] = c->ambient/(pk->r_amb_sec_per);
5123
}
5124
5125
dCreate_Dense_Matrix(&B, m, npower_vector, *power_vector, m, SLU_DN, SLU_D, SLU_GE);
5126
5127
return B;
5128
}
5129
5130
void direct_SLU(grid_model_t *model, grid_model_vector_t *power, grid_model_vector_t *temp)
5131
{
5132
SuperMatrix A, L, U, B;
5133
double *P;
5134
int *perm_r; /* row permutations from partial pivoting */
5135
int *perm_c; /* column permutation vector */
5136
int info;
5137
superlu_options_t options;
5138
SuperLUStat_t stat;
5139
5140
int i, j, dim;
5141
DNformat *Astore;
5142
double *dp;
5143
5144
/* shortcuts */
5145
int nr = model->rows;
5146
int nc = model->cols;
5147
int nl = model->n_layers;
5148
5149
if (model->config.model_secondary)
5150
dim = nl*nr*nc + EXTRA + EXTRA_SEC;
5151
else
5152
dim = nl*nr*nc + EXTRA;
5153
5154
//A = build_steady_grid_matrix(model);
5155
//B = build_steady_rhs_vector(model, power, &power_vector);
5156
A = build_transient_grid_matrix(model);
5157
P = build_transient_power_vector(model, power);
5158
5159
if(MAKE_CSVS) {
5160
vectorTocsv("P.csv", nl*nr*nc + EXTRA, P);
5161
}
5162
5163
dCreate_Dense_Matrix(&B, dim, 1, P, dim, SLU_DN, SLU_D, SLU_GE);
5164
if ( !(perm_r = intMalloc(dim)) ) fatal("Malloc fails for perm_r[].\n");
5165
if ( !(perm_c = intMalloc(dim)) ) fatal("Malloc fails for perm_c[].\n");
5166
5167
/* Set the default input options. */
5168
set_default_options(&options);
5169
//options.ColPerm = MMD_AT_PLUS_A;
5170
//options.DiagPivotThresh = 0.01;
5171
//options.SymmetricMode = YES;
5172
//options.Equil = YES;
5173
5174
/* Initialize the statistics variables. */
5175
StatInit(&stat);
5176
5177
/* Solve the linear system. */
5178
dgssv(&options, &A, perm_c, perm_r, &L, &U, &B, &stat, &info);
5179
Astore = (DNformat *) B.Store;
5180
dp = (double *) Astore->nzval;
5181
//copy results back to last_steady
5182
for(i=0; i<dim; ++i){
5183
model->last_steady->cuboid[0][0][i] = dp[i];
5184
}
5185
5186
//SUPERLU_FREE (power_vector);
5187
SUPERLU_FREE (perm_r);
5188
SUPERLU_FREE (perm_c);
5189
Destroy_CompCol_Matrix(&A);
5190
Destroy_SuperMatrix_Store(&B);
5191
Destroy_SuperNode_Matrix(&L);
5192
Destroy_CompCol_Matrix(&U);
5193
StatFree(&stat);
5194
}
5195
5196
SuperMatrix build_transient_grid_matrix(grid_model_t *model)
5197
{
5198
SuperMatrix A;
5199
double *a;
5200
int *asub, *xa;
5201
double *cooV;
5202
int *cooX, *cooY;
5203
5204
int i, j, l, m, n, nnz;
5205
double dia_val;
5206
int curidx, grididx;
5207
int xoffset, yoffset;
5208
double Rn, Rs, Rw, Re, Ra, Rb;
5209
double Rx, Ry, Rz;
5210
double R_temp;
5211
double Jn, Js, Je, Jw, Jc;
5212
5213
/* shortcuts */
5214
int nr = model->rows;
5215
int nc = model->cols;
5216
int nl = model->n_layers;
5217
int spidx, hsidx, subidx, solderidx, pcbidx;
5218
int model_secondary = model->config.model_secondary;
5219
double cw = model->width / model->cols;
5220
double ch = model->height / model->rows;
5221
layer_t *lyr = model->layers;
5222
package_RC_t *pk = &model->pack;
5223
5224
spidx = nl - DEFAULT_PACK_LAYERS + LAYER_SP;
5225
hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
5226
if(model_secondary){
5227
subidx = LAYER_SUB;
5228
solderidx = LAYER_SOLDER;
5229
pcbidx = LAYER_PCB;
5230
}
5231
5232
/* Initialize matrix A. */
5233
if(model_secondary){
5234
m = n = (nl*nc*nr + EXTRA + EXTRA_SEC);
5235
/* Num of non-zeros
5236
* each layer Five diagonal : c*r, c*(r-1), (c-1)*r, c*(r-1), (c-1)*r
5237
* vertical connections : 2*(nl-1)*nr*nc
5238
* layer peripheral : 5 * 2 * (2*nr+2*nc)
5239
* diaganal for pkg nodes : EXTRA + EXTRA_SEC
5240
* between prim pkg nodes : 2 * 2 * 4
5241
* between sec pkg nodes : 3 * 2 * 4
5242
*/
5243
nnz = 5*nr*nc-2*(nr+nc);
5244
nnz *= nl;
5245
nnz += 2*(nl-1)*nr*nc;
5246
nnz += 5*2*2*(nr+nc);
5247
nnz += EXTRA + EXTRA_SEC;
5248
nnz += 16 + 24;
5249
}
5250
else{
5251
m = n = (nl*nc*nr + EXTRA);
5252
/* Num of non-zeros
5253
* each layer Five diagonal : c*r, c*(r-1), (c-1)*r, c*(r-1), (c-1)*r
5254
* vertical connections : 2*(nl-1)*nr*nc
5255
* sp and hs layer peripheral: 2 * 2 * (2*nr+2*nc)
5256
* diaganal for pkg nodes : EXTRA
5257
* between pkg nodes : 2 * 2 * 4
5258
*/
5259
nnz = 5*nr*nc-2*(nr+nc);
5260
nnz *= nl;
5261
nnz += 2*(nl-1)*nr*nc;
5262
nnz += 2*2*2*(nr+nc);
5263
nnz += EXTRA + 16;
5264
}
5265
5266
if ( !(cooV = doubleMalloc(nnz)) ) fatal("Malloc fails for cooV[].\n");
5267
if ( !(cooX = intMalloc(nnz)) ) fatal("Malloc fails for cooX[].\n");
5268
if ( !(cooY = intMalloc(nnz)) ) fatal("Malloc fails for cooY[].\n");
5269
5270
if ( !(a = doubleMalloc(nnz)) ) fatal("Malloc fails for a[].\n");
5271
if ( !(asub = intMalloc(nnz)) ) fatal("Malloc fails for asub[].\n");
5272
if ( !(xa = intMalloc(n+1)) ) fatal("Malloc fails for xa[].\n");
5273
5274
curidx = 0;
5275
for(l=0; l<nl; l++){
5276
xoffset = l*nr*nc;
5277
yoffset = l*nr*nc;
5278
for(i=0; i<nr; i++){
5279
for(j=0; j<nc; j++){
5280
grididx = i*nc + j;
5281
5282
if(model->config.detailed_3D_used == 1){
5283
if(j > 0) Rw = find_res(model, l, i, j-1, l, i, j); else Rw = LARGENUM;
5284
if(j < nc-1) Re = find_res(model, l, i, j+1, l, i, j); else Re = LARGENUM;
5285
if(i > 0) Rn = find_res(model, l, i-1, j, l, i, j); else Rn = LARGENUM;
5286
if(i < nr-1) Rs = find_res(model, l, i+1, j, l, i, j); else Rs = LARGENUM;
5287
if(l > 0) Ra = find_res(model, l-1, i, j, l, i, j); else Ra = LARGENUM;
5288
if(l < nl-1) Rb = find_res(model, l+1, i, j, l, i, j); else Rb = LARGENUM;
5289
}
5290
else{
5291
if(j > 0) Rw = find_res(model, l, i, j-1, l, i, j); else Rw = LARGENUM;
5292
if(j < nc-1) Re = find_res(model, l, i, j+1, l, i, j); else Re = LARGENUM;
5293
if(i > 0) Rn = find_res(model, l, i-1, j, l, i, j); else Rn = LARGENUM;
5294
if(i < nr-1) Rs = find_res(model, l, i+1, j, l, i, j); else Rs = LARGENUM;
5295
if(l > 0) Ra = find_res(model, l-1, i, j, l, i, j); else Ra = LARGENUM;
5296
if(l < nl-1) Rb = find_res(model, l+1, i, j, l, i, j); else Rb = LARGENUM;
5297
}
5298
/* If this layer has microchannels, compute the appropriate current
5299
* source values
5300
*/
5301
5302
/*
5303
fprintf(stderr, "(%d, %d, %d):\n", l, i, j);
5304
fprintf(stderr, " Rw = %e\n", Rw);
5305
fprintf(stderr, " Re = %e\n", Re);
5306
fprintf(stderr, " Rn = %e\n", Rn);
5307
fprintf(stderr, " Rs = %e\n", Rs);
5308
fprintf(stderr, " Ra = %e\n", Ra);
5309
fprintf(stderr, " Rb = %e\n", Rb);
5310
*/
5311
5312
Jn = Js = Je = Jw = Jc = 0.0;
5313
if(model->layers[l].is_microchannel) {
5314
microchannel_config_t *uconf = model->layers[l].microchannel_config;
5315
double coeff;
5316
// For now I'm going to assume that an outlet only has one fluid cell adjacent to it
5317
if(IS_OUTLET_CELL(uconf, i, j)) {
5318
// Northern fluid cell
5319
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
5320
coeff = uconf->coolant_capac * flow_rate(uconf, i-1, j, i, j);
5321
Jn -= coeff / 2.0;
5322
Jc += coeff / 2.0;
5323
}
5324
5325
// Southern fluid cell
5326
else if (i < nr - 1 && IS_FLUID_CELL(uconf, i+1, j)) {
5327
coeff = uconf->coolant_capac * flow_rate(uconf, i+1, j, i, j);
5328
Js -= coeff / 2.0;
5329
Jc += coeff / 2.0;
5330
}
5331
5332
// Western fluid cell
5333
else if (j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
5334
coeff = uconf->coolant_capac * flow_rate(uconf, i, j-1, i, j);
5335
Jw -= coeff / 2.0;
5336
Jc += coeff / 2.0;
5337
}
5338
5339
// Eastern fluid cell
5340
else if (j < nc - 1 && IS_FLUID_CELL(uconf, i, j+1)) {
5341
coeff = uconf->coolant_capac * flow_rate(uconf, i, j+1, i, j);
5342
Je -= coeff / 2.0;
5343
Jc += coeff / 2.0;
5344
}
5345
}
5346
5347
else if(IS_FLUID_CELL(uconf, i, j)) {
5348
// northern cell
5349
if(i > 0) {
5350
if(IS_FLUID_CELL(uconf, i-1, j)) {
5351
coeff = uconf->coolant_capac * flow_rate(uconf, i, j, i-1, j);
5352
Jn += coeff / 2.0;
5353
Jc += coeff / 2.0;
5354
//fprintf(stderr, "[Northern] coeff = %e * %e = %e\n", uconf->coolant_capac, flow_rate(uconf, i, j, i-1, j), coeff);
5355
//Jn += coeff * ((A3D(v,l,i,j,nl,nr,nc) + A3D(v,l,i-1,j,nl,nr,nc)) / 2.0);
5356
}
5357
}
5358
5359
// southern cell
5360
if(i < nr - 1) {
5361
if(IS_FLUID_CELL(uconf, i+1, j)) {
5362
coeff = uconf->coolant_capac * flow_rate(uconf, i, j, i+1, j);
5363
Js += coeff / 2.0;
5364
Jc += coeff / 2.0;
5365
//fprintf(stderr, "[Southern] coeff = %e * %e = %e\n", uconf->coolant_capac, flow_rate(uconf, i, j, i+1, j), coeff);
5366
//Js += coeff * ((A3D(v,l,i,j,nl,nr,nc) + A3D(v,l,i+1,j,nl,nr,nc)) / 2.0);
5367
}
5368
}
5369
5370
// western cell
5371
if(j > 0) {
5372
if(IS_FLUID_CELL(uconf, i, j-1)) {
5373
coeff = uconf->coolant_capac * flow_rate(uconf, i, j, i, j-1);
5374
Jw += coeff / 2.0;
5375
Jc += coeff / 2.0;
5376
//Jw += coeff * ((A3D(v,l,i,j,nl,nr,nc) + A3D(v,l,i,j-1,nl,nr,nc)) / 2.0);
5377
}
5378
}
5379
5380
// eastern cell
5381
if(j < nc - 1) {
5382
if(IS_FLUID_CELL(uconf, i, j+1)) {
5383
coeff = uconf->coolant_capac * flow_rate(uconf, i, j, i, j+1);
5384
Je += coeff / 2.0;
5385
Jc += coeff / 2.0;
5386
//Je += coeff * ((A3D(v,l,i,j,nl,nr,nc) + A3D(v,l,i,j+1,nl,nr,nc)) / 2.0);
5387
}
5388
}
5389
}
5390
}
5391
5392
/* fprintf(stderr, " Jw = %e\n", Jw);
5393
fprintf(stderr, " Je = %e\n", Je);
5394
fprintf(stderr, " Jn = %e\n", Jn);
5395
fprintf(stderr, " Js = %e\n", Js);
5396
fprintf(stderr, " Jc = %e\n", Jc);
5397
*/
5398
dia_val = 0;
5399
if(0 == grididx){//top left corner
5400
//fprintf(stderr, "Top Left Corner\n");
5401
5402
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
5403
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx+1+yoffset, curidx, -1.0/Re + Je);
5404
cooV[curidx] = -1.0/Re + Je; curidx++; dia_val += 1.0/Re;
5405
5406
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
5407
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx+nc+yoffset, curidx, -1.0/Rs + Js);
5408
cooV[curidx] = -1.0/Rs + Js; curidx++; dia_val += 1.0/Rs;
5409
5410
if(l<nl-1){
5411
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5412
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5413
}
5414
if(l>0){
5415
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5416
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5417
}
5418
5419
if(l == spidx){
5420
/* northern boundary - edge cell has half the ry */
5421
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
5422
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_N;
5423
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5424
/* western boundary - edge cell has half the rx */
5425
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
5426
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_W;
5427
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5428
}
5429
else if(l == hsidx){
5430
/* northern boundary - edge cell has half the ry */
5431
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
5432
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_N;
5433
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5434
/* western boundary - edge cell has half the rx */
5435
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
5436
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_W;
5437
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5438
5439
/* all nodes are connected to the ambient */
5440
R_temp = lyr[l].rz;
5441
dia_val += 1.0/R_temp;
5442
}
5443
else if ((l==subidx) && model_secondary) {
5444
/* northern boundary - edge cell has half the ry */
5445
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
5446
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_N;
5447
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5448
/* western boundary - edge cell has half the rx */
5449
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
5450
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_W;
5451
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5452
}
5453
else if ((l==solderidx) && model_secondary) {
5454
/* northern boundary - edge cell has half the ry */
5455
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
5456
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_N;
5457
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5458
/* western boundary - edge cell has half the rx */
5459
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
5460
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_W;
5461
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5462
}
5463
else if ((l==pcbidx) && model_secondary) {
5464
/* northern boundary - edge cell has half the ry */
5465
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
5466
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_N;
5467
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5468
/* western boundary - edge cell has half the rx */
5469
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
5470
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_W;
5471
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5472
5473
/* all nodes are connected to the ambient */
5474
R_temp = model->config.r_convec_sec * \
5475
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5476
dia_val += 1.0/R_temp;
5477
}
5478
5479
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5480
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx+yoffset, curidx, dia_val + Jc);
5481
cooV[curidx] = dia_val + Jc; curidx++;
5482
}
5483
else if((nc-1) == grididx ){//top right corner
5484
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
5485
cooV[curidx] = -1.0/Rw + Jw; curidx++; dia_val += 1.0/Rw;
5486
5487
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
5488
cooV[curidx] = -1.0/Rs + Js; curidx++; dia_val += 1.0/Rs;
5489
5490
if(l<nl-1){
5491
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5492
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5493
}
5494
if(l>0){
5495
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5496
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5497
}
5498
5499
if(l == spidx){
5500
/* northern boundary - edge cell has half the ry */
5501
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
5502
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_N;
5503
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5504
/* eastern boundary - edge cell has half the rx */
5505
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
5506
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_E;
5507
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5508
}
5509
else if(l == hsidx){
5510
/* northern boundary - edge cell has half the ry */
5511
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
5512
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_N;
5513
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5514
/* eastern boundary - edge cell has half the rx */
5515
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
5516
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_E;
5517
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5518
5519
/* all nodes are connected to the ambient */
5520
R_temp = lyr[l].rz;
5521
dia_val += 1.0/R_temp;
5522
}
5523
else if ((l==subidx) && model_secondary) {
5524
/* northern boundary - edge cell has half the ry */
5525
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
5526
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_N;
5527
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5528
/* eastern boundary - edge cell has half the rx */
5529
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
5530
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_E;
5531
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5532
}
5533
else if ((l==solderidx) && model_secondary) {
5534
/* northern boundary - edge cell has half the ry */
5535
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
5536
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_N;
5537
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5538
/* eastern boundary - edge cell has half the rx */
5539
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
5540
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_E;
5541
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5542
}
5543
else if ((l==pcbidx) && model_secondary) {
5544
/* northern boundary - edge cell has half the ry */
5545
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
5546
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_N;
5547
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5548
/* eastern boundary - edge cell has half the rx */
5549
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
5550
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_E;
5551
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5552
5553
/* all nodes are connected to the ambient */
5554
R_temp = model->config.r_convec_sec * \
5555
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5556
dia_val += 1.0/R_temp;
5557
}
5558
5559
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5560
cooV[curidx] = dia_val + Jc; curidx++;
5561
}
5562
else if((nr*nc-nc) == grididx){//bottom left corner
5563
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
5564
cooV[curidx] = -1.0/Re + Je; curidx++; dia_val += 1.0/Re;
5565
5566
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
5567
cooV[curidx] = -1.0/Rn + Jn; curidx++; dia_val += 1.0/Rn;
5568
5569
if(l<nl-1){
5570
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5571
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5572
}
5573
if(l>0){
5574
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5575
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5576
}
5577
5578
if(l == spidx){
5579
/* southern boundary - edge cell has half the ry */
5580
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
5581
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_S;
5582
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5583
/* western boundary - edge cell has half the rx */
5584
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
5585
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_W;
5586
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5587
}
5588
else if(l == hsidx){
5589
/* southern boundary - edge cell has half the ry */
5590
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
5591
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_S;
5592
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5593
/* western boundary - edge cell has half the rx */
5594
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
5595
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_W;
5596
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5597
5598
/* all nodes are connected to the ambient */
5599
R_temp = lyr[l].rz;
5600
dia_val += 1.0/R_temp;
5601
}
5602
else if ((l==subidx) && model_secondary) {
5603
/* southern boundary - edge cell has half the ry */
5604
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
5605
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_S;
5606
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5607
/* western boundary - edge cell has half the rx */
5608
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
5609
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_W;
5610
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5611
}
5612
else if ((l==solderidx) && model_secondary) {
5613
/* southern boundary - edge cell has half the ry */
5614
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
5615
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_S;
5616
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5617
/* western boundary - edge cell has half the rx */
5618
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
5619
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_W;
5620
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5621
}
5622
else if ((l==pcbidx) && model_secondary) {
5623
/* southern boundary - edge cell has half the ry */
5624
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
5625
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_S;
5626
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5627
/* western boundary - edge cell has half the rx */
5628
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
5629
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_W;
5630
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5631
5632
/* all nodes are connected to the ambient */
5633
R_temp = model->config.r_convec_sec * \
5634
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5635
dia_val += 1.0/R_temp;
5636
}
5637
5638
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5639
cooV[curidx] = dia_val + Jc; curidx++;
5640
}
5641
else if((nr*nc-1) == grididx){//bottom right corner
5642
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
5643
cooV[curidx] = -1.0/Rw + Jw; curidx++; dia_val += 1.0/Rw;
5644
5645
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
5646
cooV[curidx] = -1.0/Rn + Jn; curidx++; dia_val += 1.0/Rn;
5647
5648
if(l<nl-1){
5649
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5650
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5651
}
5652
if(l>0){
5653
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5654
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5655
}
5656
5657
if(l == spidx){
5658
/* southern boundary - edge cell has half the ry */
5659
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
5660
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_S;
5661
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5662
/* eastern boundary - edge cell has half the rx */
5663
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
5664
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_E;
5665
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5666
}
5667
else if(l == hsidx){
5668
/* southern boundary - edge cell has half the ry */
5669
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
5670
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_S;
5671
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5672
/* eastern boundary - edge cell has half the rx */
5673
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
5674
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_E;
5675
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5676
5677
/* all nodes are connected to the ambient */
5678
R_temp = lyr[l].rz;
5679
dia_val += 1.0/R_temp;
5680
}
5681
else if ((l==subidx) && model_secondary) {
5682
/* southern boundary - edge cell has half the ry */
5683
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
5684
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_S;
5685
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5686
/* eastern boundary - edge cell has half the rx */
5687
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
5688
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_E;
5689
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5690
}
5691
else if ((l==solderidx) && model_secondary) {
5692
/* southern boundary - edge cell has half the ry */
5693
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
5694
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_S;
5695
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5696
/* eastern boundary - edge cell has half the rx */
5697
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
5698
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_E;
5699
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5700
}
5701
else if ((l==pcbidx) && model_secondary) {
5702
/* southern boundary - edge cell has half the ry */
5703
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
5704
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_S;
5705
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5706
/* eastern boundary - edge cell has half the rx */
5707
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
5708
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_E;
5709
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5710
5711
/* all nodes are connected to the ambient */
5712
R_temp = model->config.r_convec_sec * \
5713
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5714
dia_val += 1.0/R_temp;
5715
}
5716
5717
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5718
cooV[curidx] = dia_val + Jc; curidx++;
5719
}
5720
else if((grididx > 0) && (grididx < nc-1)){//top row
5721
//fprintf(stderr, "Top Row\n");
5722
5723
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
5724
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx-1+yoffset, curidx, -1.0/Rw + Jw);
5725
cooV[curidx] = -1.0/Rw + Jw; curidx++; dia_val += 1.0/Rw;
5726
5727
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
5728
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx+1+yoffset, curidx, -1.0/Re + Je);
5729
cooV[curidx] = -1.0/Re + Je; curidx++; dia_val += 1.0/Re;
5730
5731
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
5732
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx+nc+yoffset, curidx, -1.0/Rs + Js);
5733
cooV[curidx] = -1.0/Rs + Js; curidx++; dia_val += 1.0/Rs;
5734
5735
if(l<nl-1){
5736
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5737
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5738
}
5739
if(l>0){
5740
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5741
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5742
}
5743
5744
if(l == spidx){
5745
/* northern boundary - edge cell has half the ry */
5746
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
5747
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_N;
5748
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5749
}
5750
else if(l == hsidx){
5751
/* northern boundary - edge cell has half the ry */
5752
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
5753
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_N;
5754
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5755
5756
/* all nodes are connected to the ambient */
5757
R_temp = lyr[l].rz;
5758
dia_val += 1.0/R_temp;
5759
}
5760
else if ((l==subidx) && model_secondary) {
5761
/* northern boundary - edge cell has half the ry */
5762
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
5763
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_N;
5764
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5765
}
5766
else if ((l==solderidx) && model_secondary) {
5767
/* northern boundary - edge cell has half the ry */
5768
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
5769
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_N;
5770
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5771
}
5772
else if ((l==pcbidx) && model_secondary) {
5773
/* northern boundary - edge cell has half the ry */
5774
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
5775
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_N;
5776
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5777
5778
/* all nodes are connected to the ambient */
5779
R_temp = model->config.r_convec_sec * \
5780
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5781
dia_val += 1.0/R_temp;
5782
}
5783
5784
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5785
//fprintf(stderr, "cooX[%d] = %d; cooY[%d] = %d; cooV[%d] = %e\n", curidx, grididx+xoffset, curidx, grididx+yoffset, curidx, dia_val + Jc);
5786
cooV[curidx] = dia_val + Jc; curidx++;
5787
}
5788
else if((grididx > nr*nc-nc) && (grididx < nr*nc-1)){//bottom row
5789
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
5790
cooV[curidx] = -1.0/Rw + Jw; curidx++; dia_val += 1.0/Rw;
5791
5792
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
5793
cooV[curidx] = -1.0/Re + Je; curidx++; dia_val += 1.0/Re;
5794
5795
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
5796
cooV[curidx] = -1.0/Rn + Jn; curidx++; dia_val += 1.0/Rn;
5797
5798
if(l<nl-1){
5799
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5800
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5801
}
5802
if(l>0){
5803
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5804
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5805
}
5806
5807
if(l == spidx){
5808
/* southern boundary - edge cell has half the ry */
5809
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sp1_y;
5810
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_S;
5811
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5812
}
5813
else if(l == hsidx){
5814
/* southern boundary - edge cell has half the ry */
5815
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_hs1_y;
5816
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_S;
5817
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5818
5819
/* all nodes are connected to the ambient */
5820
R_temp = lyr[l].rz;
5821
dia_val += 1.0/R_temp;
5822
}
5823
else if ((l==subidx) && model_secondary) {
5824
/* southern boundary - edge cell has half the ry */
5825
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_sub1_y;
5826
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_S;
5827
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5828
}
5829
else if ((l==solderidx) && model_secondary) {
5830
/* southern boundary - edge cell has half the ry */
5831
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_solder1_y;
5832
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_S;
5833
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5834
}
5835
else if ((l==pcbidx) && model_secondary) {
5836
/* southern boundary - edge cell has half the ry */
5837
R_temp = lyr[l].ry/2.0 + nc*model->pack.r_pcb1_y;
5838
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_S;
5839
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5840
5841
/* all nodes are connected to the ambient */
5842
R_temp = model->config.r_convec_sec * \
5843
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5844
dia_val += 1.0/R_temp;
5845
}
5846
5847
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5848
cooV[curidx] = dia_val + Jc; curidx++;
5849
}
5850
else if(0 == (grididx%nc)){//leftmost column
5851
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
5852
cooV[curidx] = -1.0/Rn + Jn; curidx++; dia_val += 1.0/Rn;
5853
5854
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
5855
cooV[curidx] = -1.0/Rs + Js; curidx++; dia_val += 1.0/Rs;
5856
5857
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
5858
cooV[curidx] = -1.0/Re + Je; curidx++; dia_val += 1.0/Re;
5859
5860
if(l<nl-1){
5861
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5862
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5863
}
5864
if(l>0){
5865
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5866
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5867
}
5868
5869
if(l == spidx){
5870
/* western boundary - edge cell has half the rx */
5871
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
5872
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_W;
5873
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5874
}
5875
else if(l == hsidx){
5876
/* western boundary - edge cell has half the rx */
5877
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
5878
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_W;
5879
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5880
5881
/* all nodes are connected to the ambient */
5882
R_temp = lyr[l].rz;
5883
dia_val += 1.0/R_temp;
5884
}
5885
else if ((l==subidx) && model_secondary) {
5886
/* western boundary - edge cell has half the rx */
5887
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
5888
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_W;
5889
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5890
}
5891
else if ((l==solderidx) && model_secondary) {
5892
/* western boundary - edge cell has half the rx */
5893
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
5894
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_W;
5895
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5896
}
5897
else if ((l==pcbidx) && model_secondary) {
5898
/* western boundary - edge cell has half the rx */
5899
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
5900
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_W;
5901
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5902
5903
/* all nodes are connected to the ambient */
5904
R_temp = model->config.r_convec_sec * \
5905
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5906
dia_val += 1.0/R_temp;
5907
}
5908
5909
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5910
cooV[curidx] = dia_val + Jc; curidx++;
5911
}
5912
else if(0 == ((grididx+1)%nc)){//rightmost column
5913
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
5914
cooV[curidx] = -1.0/Rn + Jn; curidx++; dia_val += 1.0/Rn;
5915
5916
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
5917
cooV[curidx] = -1.0/Rs + Js; curidx++; dia_val += 1.0/Rs;
5918
5919
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
5920
cooV[curidx] = -1.0/Rw + Jw; curidx++; dia_val += 1.0/Rw;
5921
5922
if(l<nl-1){
5923
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5924
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5925
}
5926
if(l>0){
5927
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5928
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5929
}
5930
5931
if(l == spidx){
5932
/* eastern boundary - edge cell has half the rx */
5933
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sp1_x;
5934
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SP_E;
5935
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5936
}
5937
else if(l == hsidx){
5938
/* eastern boundary - edge cell has half the rx */
5939
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_hs1_x;
5940
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SINK_C_E;
5941
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5942
5943
/* all nodes are connected to the ambient */
5944
R_temp = lyr[l].rz;
5945
dia_val += 1.0/R_temp;
5946
}
5947
else if ((l==subidx) && model_secondary) {
5948
/* eastern boundary - edge cell has half the rx */
5949
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_sub1_x;
5950
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SUB_E;
5951
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5952
}
5953
else if ((l==solderidx) && model_secondary) {
5954
/* eastern boundary - edge cell has half the rx */
5955
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_solder1_x;
5956
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + SOLDER_E;
5957
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5958
}
5959
else if ((l==pcbidx) && model_secondary) {
5960
/* eastern boundary - edge cell has half the rx */
5961
R_temp = lyr[l].rx/2.0 + nr*model->pack.r_pcb1_x;
5962
cooX[curidx] = grididx+xoffset; cooY[curidx] = nl*nr*nc + PCB_C_E;
5963
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
5964
5965
/* all nodes are connected to the ambient */
5966
R_temp = model->config.r_convec_sec * \
5967
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
5968
dia_val += 1.0/R_temp;
5969
}
5970
5971
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
5972
cooV[curidx] = dia_val + Jc; curidx++;
5973
}
5974
else{//central grid cell
5975
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nc+yoffset;
5976
cooV[curidx] = -1.0/Rn + Jn; curidx++; dia_val += 1.0/Rn;
5977
5978
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nc+yoffset;
5979
cooV[curidx] = -1.0/Rs + Js; curidx++; dia_val += 1.0/Rs;
5980
5981
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-1+yoffset;
5982
cooV[curidx] = -1.0/Rw + Jw; curidx++; dia_val += 1.0/Rw;
5983
5984
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+1+yoffset;
5985
cooV[curidx] = -1.0/Re + Je; curidx++; dia_val += 1.0/Re;
5986
5987
if(l<nl-1){
5988
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+nr*nc+yoffset;
5989
cooV[curidx] = -1.0/Rb; curidx++; dia_val += 1.0/Rb;
5990
}
5991
if(l>0){
5992
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx-nr*nc+yoffset;
5993
cooV[curidx] = -1.0/Ra; curidx++; dia_val += 1.0/Ra;
5994
}
5995
5996
if(l == hsidx){
5997
/* all nodes are connected to the ambient */
5998
R_temp = lyr[l].rz;
5999
dia_val += 1.0/R_temp;
6000
}
6001
else if ((l==pcbidx) && model_secondary) {
6002
/* all nodes are connected to the ambient */
6003
R_temp = model->config.r_convec_sec * \
6004
(model->config.s_pcb * model->config.s_pcb) / (cw * ch);
6005
dia_val += 1.0/R_temp;
6006
}
6007
6008
cooX[curidx] = grididx+xoffset; cooY[curidx] = grididx+yoffset;
6009
cooV[curidx] = dia_val + Jc; curidx++;
6010
}
6011
}
6012
}
6013
}
6014
6015
/* Package nodes */
6016
/* sink outer north/south */
6017
xoffset = nl*nr*nc;
6018
yoffset = nl*nr*nc;
6019
dia_val = 0;
6020
R_temp = pk->r_hs2_y + pk->r_hs;
6021
cooX[curidx] = SINK_N+xoffset; cooY[curidx] = SINK_C_N+yoffset;
6022
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6023
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
6024
cooX[curidx] = SINK_N+xoffset; cooY[curidx] = SINK_N+yoffset;
6025
cooV[curidx] = dia_val; curidx++;
6026
6027
dia_val = 0;
6028
R_temp = pk->r_hs2_y + pk->r_hs;
6029
cooX[curidx] = SINK_S+xoffset; cooY[curidx] = SINK_C_S+yoffset;
6030
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6031
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
6032
cooX[curidx] = SINK_S+xoffset; cooY[curidx] = SINK_S+yoffset;
6033
cooV[curidx] = dia_val; curidx++;
6034
6035
/* sink outer west/east */
6036
dia_val = 0;
6037
R_temp = pk->r_hs2_x + pk->r_hs;
6038
cooX[curidx] = SINK_W+xoffset; cooY[curidx] = SINK_C_W+yoffset;
6039
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6040
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
6041
cooX[curidx] = SINK_W+xoffset; cooY[curidx] = SINK_W+yoffset;
6042
cooV[curidx] = dia_val; curidx++;
6043
6044
dia_val = 0;
6045
R_temp = pk->r_hs2_x + pk->r_hs;
6046
cooX[curidx] = SINK_E+xoffset; cooY[curidx] = SINK_C_E+yoffset;
6047
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6048
R_temp = pk->r_hs_per + pk->r_amb_per; dia_val += 1.0/R_temp;
6049
cooX[curidx] = SINK_E+xoffset; cooY[curidx] = SINK_E+yoffset;
6050
cooV[curidx] = dia_val; curidx++;
6051
6052
/* sink inner north/south */
6053
xoffset = nl*nr*nc;
6054
yoffset = hsidx*nr*nc;
6055
dia_val = 0;
6056
for(i=0, j=0; j < nc; j++){
6057
grididx = i*nc + j;
6058
R_temp = lyr[hsidx].ry / 2.0 + nc * pk->r_hs1_y;
6059
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = grididx+yoffset;
6060
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6061
}
6062
xoffset = nl*nr*nc;
6063
yoffset = nl*nr*nc;
6064
R_temp = pk->r_sp_per_y;
6065
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = SP_N+yoffset;
6066
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6067
R_temp = pk->r_hs2_y + pk->r_hs;
6068
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = SINK_N+yoffset;
6069
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6070
R_temp = pk->r_hs_c_per_y + pk->r_amb_c_per_y; dia_val += 1.0/R_temp;
6071
cooX[curidx] = SINK_C_N+xoffset; cooY[curidx] = SINK_C_N+yoffset;
6072
cooV[curidx] = dia_val; curidx++;
6073
6074
xoffset = nl*nr*nc;
6075
yoffset = hsidx*nr*nc;
6076
dia_val = 0;
6077
for(i=nr-1, j=0; j < nc; j++){
6078
grididx = i*nc + j;
6079
R_temp = lyr[hsidx].ry / 2.0 + nc * pk->r_hs1_y;
6080
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = grididx+yoffset;
6081
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6082
}
6083
xoffset = nl*nr*nc;
6084
yoffset = nl*nr*nc;
6085
R_temp = pk->r_sp_per_y;
6086
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = SP_S+yoffset;
6087
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6088
R_temp = pk->r_hs2_y + pk->r_hs;
6089
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = SINK_S+yoffset;
6090
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6091
R_temp = pk->r_hs_c_per_y + pk->r_amb_c_per_y; dia_val += 1.0/R_temp;
6092
cooX[curidx] = SINK_C_S+xoffset; cooY[curidx] = SINK_C_S+yoffset;
6093
cooV[curidx] = dia_val; curidx++;
6094
6095
/* sink inner west/east */
6096
xoffset = nl*nr*nc;
6097
yoffset = hsidx*nr*nc;
6098
dia_val = 0;
6099
for(i=0, j=0; i < nr; i++){
6100
grididx = i*nc + j;
6101
R_temp = lyr[hsidx].rx / 2.0 + nr * pk->r_hs1_x;
6102
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = grididx+yoffset;
6103
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6104
}
6105
xoffset = nl*nr*nc;
6106
yoffset = nl*nr*nc;
6107
R_temp = pk->r_sp_per_x;
6108
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = SP_W+yoffset;
6109
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6110
R_temp = pk->r_hs2_x + pk->r_hs;
6111
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = SINK_W+yoffset;
6112
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6113
R_temp = pk->r_hs_c_per_x + pk->r_amb_c_per_x; dia_val += 1.0/R_temp;
6114
6115
cooX[curidx] = SINK_C_W+xoffset; cooY[curidx] = SINK_C_W+yoffset;
6116
cooV[curidx] = dia_val; curidx++;
6117
6118
xoffset = nl*nr*nc;
6119
yoffset = hsidx*nr*nc;
6120
dia_val = 0;
6121
for(i=0, j=nc-1; i < nr; i++){
6122
grididx = i*nc + j;
6123
R_temp = lyr[hsidx].rx / 2.0 + nr * pk->r_hs1_x;
6124
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = grididx+yoffset;
6125
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6126
}
6127
xoffset = nl*nr*nc;
6128
yoffset = nl*nr*nc;
6129
R_temp = pk->r_sp_per_x;
6130
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = SP_E+yoffset;
6131
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6132
R_temp = pk->r_hs2_x + pk->r_hs;
6133
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = SINK_E+yoffset;
6134
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6135
R_temp = pk->r_hs_c_per_x + pk->r_amb_c_per_x; dia_val += 1.0/R_temp;
6136
cooX[curidx] = SINK_C_E+xoffset; cooY[curidx] = SINK_C_E+yoffset;
6137
cooV[curidx] = dia_val; curidx++;
6138
6139
/* spreader north/south */
6140
xoffset = nl*nr*nc;
6141
yoffset = spidx*nr*nc;
6142
dia_val = 0;
6143
for(i=0, j=0; j < nc; j++){
6144
grididx = i*nc + j;
6145
R_temp = lyr[spidx].ry / 2.0 + nc * pk->r_sp1_y;
6146
cooX[curidx] = SP_N+xoffset; cooY[curidx] = grididx+yoffset;
6147
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6148
}
6149
xoffset = nl*nr*nc;
6150
yoffset = nl*nr*nc;
6151
R_temp = pk->r_sp_per_y;
6152
cooX[curidx] = SP_N+xoffset; cooY[curidx] = SINK_C_N+yoffset;
6153
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6154
6155
cooX[curidx] = SP_N+xoffset; cooY[curidx] = SP_N+yoffset;
6156
cooV[curidx] = dia_val; curidx++;
6157
6158
xoffset = nl*nr*nc;
6159
yoffset = spidx*nr*nc;
6160
dia_val = 0;
6161
for(i=nr-1, j=0; j < nc; j++){
6162
grididx = i*nc + j;
6163
R_temp = lyr[spidx].ry / 2.0 + nc * pk->r_sp1_y;
6164
cooX[curidx] = SP_S+xoffset; cooY[curidx] = grididx+yoffset;
6165
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6166
}
6167
xoffset = nl*nr*nc;
6168
yoffset = nl*nr*nc;
6169
R_temp = pk->r_sp_per_y;
6170
cooX[curidx] = SP_S+xoffset; cooY[curidx] = SINK_C_S+yoffset;
6171
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6172
6173
cooX[curidx] = SP_S+xoffset; cooY[curidx] = SP_S+yoffset;
6174
cooV[curidx] = dia_val; curidx++;
6175
6176
/* spreader west/east */
6177
xoffset = nl*nr*nc;
6178
yoffset = spidx*nr*nc;
6179
dia_val = 0;
6180
for(i=0, j=0; i < nr; i++){
6181
grididx = i*nc + j;
6182
R_temp = lyr[spidx].rx / 2.0 + nr * pk->r_sp1_x;
6183
cooX[curidx] = SP_W+xoffset; cooY[curidx] = grididx+yoffset;
6184
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6185
}
6186
xoffset = nl*nr*nc;
6187
yoffset = nl*nr*nc;
6188
R_temp = pk->r_sp_per_x;
6189
cooX[curidx] = SP_W+xoffset; cooY[curidx] = SINK_C_W+yoffset;
6190
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6191
6192
cooX[curidx] = SP_W+xoffset; cooY[curidx] = SP_W+yoffset;
6193
cooV[curidx] = dia_val; curidx++;
6194
6195
xoffset = nl*nr*nc;
6196
yoffset = spidx*nr*nc;
6197
dia_val = 0;
6198
for(i=0, j=nc-1; i < nr; i++){
6199
grididx = i*nc + j;
6200
R_temp = lyr[spidx].rx / 2.0 + nr * pk->r_sp1_x;
6201
cooX[curidx] = SP_E+xoffset; cooY[curidx] = grididx+yoffset;
6202
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6203
}
6204
xoffset = nl*nr*nc;
6205
yoffset = nl*nr*nc;
6206
R_temp = pk->r_sp_per_x;
6207
cooX[curidx] = SP_E+xoffset; cooY[curidx] = SINK_C_E+yoffset;
6208
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6209
6210
cooX[curidx] = SP_E+xoffset; cooY[curidx] = SP_E+yoffset;
6211
cooV[curidx] = dia_val; curidx++;
6212
6213
if(model_secondary){
6214
/* secondary path package nodes */
6215
/* PCB outer north/south */
6216
xoffset = nl*nr*nc;
6217
yoffset = nl*nr*nc;
6218
dia_val = 0;
6219
R_temp = pk->r_pcb2_y + pk->r_pcb;
6220
cooX[curidx] = PCB_N+xoffset; cooY[curidx] = PCB_C_N+yoffset;
6221
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6222
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
6223
cooX[curidx] = PCB_N+xoffset; cooY[curidx] = PCB_N+yoffset;
6224
cooV[curidx] = dia_val; curidx++;
6225
6226
dia_val = 0;
6227
R_temp = pk->r_pcb2_y + pk->r_pcb;
6228
cooX[curidx] = PCB_S+xoffset; cooY[curidx] = PCB_C_S+yoffset;
6229
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6230
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
6231
cooX[curidx] = PCB_S+xoffset; cooY[curidx] = PCB_S+yoffset;
6232
cooV[curidx] = dia_val; curidx++;
6233
6234
/* PCB outer west/east */
6235
dia_val = 0;
6236
R_temp = pk->r_pcb2_x + pk->r_pcb;
6237
cooX[curidx] = PCB_W+xoffset; cooY[curidx] = PCB_C_W+yoffset;
6238
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6239
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
6240
cooX[curidx] = PCB_W+xoffset; cooY[curidx] = PCB_W+yoffset;
6241
cooV[curidx] = dia_val; curidx++;
6242
6243
dia_val = 0;
6244
R_temp = pk->r_pcb2_x + pk->r_pcb;
6245
cooX[curidx] = PCB_E+xoffset; cooY[curidx] = PCB_C_E+yoffset;
6246
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6247
R_temp = pk->r_amb_sec_per; dia_val += 1.0/R_temp;
6248
cooX[curidx] = PCB_E+xoffset; cooY[curidx] = PCB_E+yoffset;
6249
cooV[curidx] = dia_val; curidx++;
6250
6251
/* PCB inner north/south */
6252
xoffset = nl*nr*nc;
6253
yoffset = pcbidx*nr*nc;
6254
dia_val = 0;
6255
for(i=0, j=0; j < nc; j++){
6256
grididx = i*nc + j;
6257
R_temp = lyr[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y;
6258
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = grididx+yoffset;
6259
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6260
}
6261
xoffset = nl*nr*nc;
6262
yoffset = nl*nr*nc;
6263
R_temp = pk->r_pcb_c_per_y;
6264
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = SOLDER_N+yoffset;
6265
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6266
R_temp = pk->r_pcb2_y + pk->r_pcb;
6267
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = PCB_N+yoffset;
6268
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6269
R_temp = pk->r_amb_sec_c_per_y; dia_val += 1.0/R_temp;
6270
6271
cooX[curidx] = PCB_C_N+xoffset; cooY[curidx] = PCB_C_N+yoffset;
6272
cooV[curidx] = dia_val; curidx++;
6273
6274
xoffset = nl*nr*nc;
6275
yoffset = pcbidx*nr*nc;
6276
dia_val = 0;
6277
for(i=nr-1, j=0; j < nc; j++){
6278
grididx = i*nc + j;
6279
R_temp = lyr[pcbidx].ry / 2.0 + nc * pk->r_pcb1_y;
6280
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = grididx+yoffset;
6281
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6282
}
6283
xoffset = nl*nr*nc;
6284
yoffset = nl*nr*nc;
6285
R_temp = pk->r_pcb_c_per_y;
6286
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = SOLDER_S+yoffset;
6287
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6288
R_temp = pk->r_pcb2_y + pk->r_pcb;
6289
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = PCB_S+yoffset;
6290
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6291
R_temp = pk->r_amb_sec_c_per_y; dia_val += 1.0/R_temp;
6292
6293
cooX[curidx] = PCB_C_S+xoffset; cooY[curidx] = PCB_C_S+yoffset;
6294
cooV[curidx] = dia_val; curidx++;
6295
6296
/* PCB inner west/east */
6297
xoffset = nl*nr*nc;
6298
yoffset = pcbidx*nr*nc;
6299
dia_val = 0;
6300
for(i=0, j=0; i < nr; i++){
6301
grididx = i*nc + j;
6302
R_temp = lyr[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x;
6303
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = grididx+yoffset;
6304
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6305
}
6306
xoffset = nl*nr*nc;
6307
yoffset = nl*nr*nc;
6308
R_temp = pk->r_pcb_c_per_x;
6309
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = SOLDER_W+yoffset;
6310
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6311
R_temp = pk->r_pcb2_x + pk->r_pcb;
6312
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = PCB_W+yoffset;
6313
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6314
R_temp = pk->r_amb_sec_c_per_x; dia_val += 1.0/R_temp;
6315
6316
cooX[curidx] = PCB_C_W+xoffset; cooY[curidx] = PCB_C_W+yoffset;
6317
cooV[curidx] = dia_val; curidx++;
6318
6319
xoffset = nl*nr*nc;
6320
yoffset = pcbidx*nr*nc;
6321
dia_val = 0;
6322
for(i=0, j=nc-1; i < nr; i++){
6323
grididx = i*nc + j;
6324
R_temp = lyr[pcbidx].rx / 2.0 + nr * pk->r_pcb1_x;
6325
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = grididx+yoffset;
6326
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6327
}
6328
xoffset = nl*nr*nc;
6329
yoffset = nl*nr*nc;
6330
R_temp = pk->r_pcb_c_per_x;
6331
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = SOLDER_E+yoffset;
6332
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6333
R_temp = pk->r_pcb2_x + pk->r_pcb;
6334
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = PCB_E+yoffset;
6335
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6336
R_temp = pk->r_amb_sec_c_per_x; dia_val += 1.0/R_temp;
6337
6338
cooX[curidx] = PCB_C_E+xoffset; cooY[curidx] = PCB_C_E+yoffset;
6339
cooV[curidx] = dia_val; curidx++;
6340
6341
/* solder north/south */
6342
xoffset = nl*nr*nc;
6343
yoffset = solderidx*nr*nc;
6344
dia_val = 0;
6345
for(i=0, j=0; j < nc; j++){
6346
grididx = i*nc + j;
6347
R_temp = lyr[solderidx].ry / 2.0 + nc * pk->r_solder1_y;
6348
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = grididx+yoffset;
6349
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6350
}
6351
xoffset = nl*nr*nc;
6352
yoffset = nl*nr*nc;
6353
R_temp = pk->r_solder_per_y;
6354
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = SUB_N+yoffset;
6355
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6356
R_temp = pk->r_pcb_c_per_y;
6357
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = PCB_C_N+yoffset;
6358
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6359
6360
cooX[curidx] = SOLDER_N+xoffset; cooY[curidx] = SOLDER_N+yoffset;
6361
cooV[curidx] = dia_val; curidx++;
6362
6363
xoffset = nl*nr*nc;
6364
yoffset = solderidx*nr*nc;
6365
dia_val = 0;
6366
for(i=nr-1, j=0; j < nc; j++){
6367
grididx = i*nc + j;
6368
R_temp = lyr[solderidx].ry / 2.0 + nc * pk->r_solder1_y;
6369
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = grididx+yoffset;
6370
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6371
}
6372
xoffset = nl*nr*nc;
6373
yoffset = nl*nr*nc;
6374
R_temp = pk->r_solder_per_y;
6375
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = SUB_S+yoffset;
6376
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6377
R_temp = pk->r_pcb_c_per_y;
6378
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = PCB_C_S+yoffset;
6379
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6380
6381
cooX[curidx] = SOLDER_S+xoffset; cooY[curidx] = SOLDER_S+yoffset;
6382
cooV[curidx] = dia_val; curidx++;
6383
6384
/* solder west/east */
6385
xoffset = nl*nr*nc;
6386
yoffset = solderidx*nr*nc;
6387
dia_val = 0;
6388
for(i=0, j=0; i < nr; i++){
6389
grididx = i*nc + j;
6390
R_temp = lyr[solderidx].rx / 2.0 + nr * pk->r_solder1_x;
6391
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = grididx+yoffset;
6392
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6393
}
6394
xoffset = nl*nr*nc;
6395
yoffset = nl*nr*nc;
6396
R_temp = pk->r_solder_per_x;
6397
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = SUB_W+yoffset;
6398
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6399
R_temp = pk->r_pcb_c_per_x;
6400
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = PCB_C_W+yoffset;
6401
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6402
6403
cooX[curidx] = SOLDER_W+xoffset; cooY[curidx] = SOLDER_W+yoffset;
6404
cooV[curidx] = dia_val; curidx++;
6405
6406
xoffset = nl*nr*nc;
6407
yoffset = solderidx*nr*nc;
6408
dia_val = 0;
6409
for(i=0, j=nc-1; i < nr; i++){
6410
grididx = i*nc + j;
6411
R_temp = lyr[solderidx].rx / 2.0 + nr * pk->r_solder1_x;
6412
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = grididx+yoffset;
6413
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6414
}
6415
xoffset = nl*nr*nc;
6416
yoffset = nl*nr*nc;
6417
R_temp = pk->r_solder_per_x;
6418
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = SUB_E+yoffset;
6419
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6420
R_temp = pk->r_pcb_c_per_x;
6421
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = PCB_C_E+yoffset;
6422
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6423
6424
cooX[curidx] = SOLDER_E+xoffset; cooY[curidx] = SOLDER_E+yoffset;
6425
cooV[curidx] = dia_val; curidx++;
6426
6427
/* substrate north/south */
6428
xoffset = nl*nr*nc;
6429
yoffset = subidx*nr*nc;
6430
dia_val = 0;
6431
for(i=0, j=0; j < nc; j++){
6432
grididx = i*nc + j;
6433
R_temp = lyr[subidx].ry / 2.0 + nc * pk->r_sub1_y;
6434
cooX[curidx] = SUB_N+xoffset; cooY[curidx] = grididx+yoffset;
6435
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6436
}
6437
xoffset = nl*nr*nc;
6438
yoffset = nl*nr*nc;
6439
R_temp = pk->r_solder_per_y;
6440
cooX[curidx] = SUB_N+xoffset; cooY[curidx] = SOLDER_N+yoffset;
6441
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6442
6443
cooX[curidx] = SUB_N+xoffset; cooY[curidx] = SUB_N+yoffset;
6444
cooV[curidx] = dia_val; curidx++;
6445
6446
xoffset = nl*nr*nc;
6447
yoffset = subidx*nr*nc;
6448
dia_val = 0;
6449
for(i=nr-1, j=0; j < nc; j++){
6450
grididx = i*nc + j;
6451
R_temp = lyr[subidx].ry / 2.0 + nc * pk->r_sub1_y;
6452
cooX[curidx] = SUB_S+xoffset; cooY[curidx] = grididx+yoffset;
6453
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6454
}
6455
xoffset = nl*nr*nc;
6456
yoffset = nl*nr*nc;
6457
R_temp = pk->r_solder_per_y;
6458
cooX[curidx] = SUB_S+xoffset; cooY[curidx] = SOLDER_S+yoffset;
6459
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6460
6461
cooX[curidx] = SUB_S+xoffset; cooY[curidx] = SUB_S+yoffset;
6462
cooV[curidx] = dia_val; curidx++;
6463
6464
/* substrate west/east */
6465
xoffset = nl*nr*nc;
6466
yoffset = subidx*nr*nc;
6467
dia_val = 0;
6468
for(i=0, j=0; i < nr; i++){
6469
grididx = i*nc + j;
6470
R_temp = lyr[subidx].rx / 2.0 + nr * pk->r_sub1_x;
6471
cooX[curidx] = SUB_W+xoffset; cooY[curidx] = grididx+yoffset;
6472
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6473
}
6474
xoffset = nl*nr*nc;
6475
yoffset = nl*nr*nc;
6476
R_temp = pk->r_solder_per_x;
6477
cooX[curidx] = SUB_W+xoffset; cooY[curidx] = SOLDER_W+yoffset;
6478
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6479
6480
cooX[curidx] = SUB_W+xoffset; cooY[curidx] = SUB_W+yoffset;
6481
cooV[curidx] = dia_val; curidx++;
6482
6483
xoffset = nl*nr*nc;
6484
yoffset = subidx*nr*nc;
6485
dia_val = 0;
6486
for(i=0, j=nc-1; i < nr; i++){
6487
grididx = i*nc + j;
6488
R_temp = lyr[subidx].rx / 2.0 + nr * pk->r_sub1_x;
6489
cooX[curidx] = SUB_E+xoffset; cooY[curidx] = grididx+yoffset;
6490
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6491
}
6492
xoffset = nl*nr*nc;
6493
yoffset = nl*nr*nc;
6494
R_temp = pk->r_solder_per_x;
6495
cooX[curidx] = SUB_E+xoffset; cooY[curidx] = SOLDER_E+yoffset;
6496
cooV[curidx] = -1.0/R_temp; curidx++; dia_val += 1.0/R_temp;
6497
6498
cooX[curidx] = SUB_E+xoffset; cooY[curidx] = SUB_E+yoffset;
6499
cooV[curidx] = dia_val; curidx++;
6500
}
6501
6502
if(curidx != nnz)
6503
fatal("Transient Matrix build error: less elements than nnz\n");
6504
6505
coo2csc(n, nnz, cooX, cooY, cooV, asub, xa, a);
6506
6507
// for(i = 0; i < nnz; i++) {
6508
// fprintf(stderr, "A[%d][%d] = %e\n", cooX[i], cooY[i], cooV[i]);
6509
// }
6510
6511
/* Create matrix A in the format expected by SuperLU. */
6512
dCreate_CompCol_Matrix(&A, m, n, nnz, a, asub, xa, SLU_NC, SLU_D, SLU_GE);
6513
6514
if(MAKE_CSVS)
6515
cooTocsv("G.csv", m, nnz, cooX, cooY, cooV);
6516
6517
free(cooV);
6518
free(cooX);
6519
free(cooY);
6520
6521
return A;
6522
}
6523
6524
double *build_transient_power_vector(grid_model_t *model, grid_model_vector_t *power)
6525
{
6526
double *power_vector;
6527
int i, j, l, n, m, idx;
6528
6529
// shortcuts
6530
int nr = model->rows;
6531
int nc = model->cols;
6532
int nl = model->n_layers;
6533
int hsidx = nl - DEFAULT_PACK_LAYERS + LAYER_SINK;
6534
int pcbidx = LAYER_PCB;
6535
int model_secondary = model->config.model_secondary;
6536
double cw = model->width / model->cols;
6537
double ch = model->height / model->rows;
6538
thermal_config_t *c = &model->config;
6539
layer_t *lyr = model->layers;
6540
package_RC_t *pk = &model->pack;
6541
6542
if(model_secondary)
6543
m = (nl*nc*nr + EXTRA + EXTRA_SEC);
6544
else
6545
m = (nl*nc*nr + EXTRA);
6546
6547
if ( !(power_vector = doubleMalloc(m)) ) fatal("Malloc fails for power_vector[].\n");
6548
6549
for(l = 0; l < nl; l++) {
6550
for(i = 0; i < nr; i++) {
6551
for(j = 0; j < nc; j++) {
6552
idx = l*nr*nc + i*nc + j;
6553
6554
if(l == hsidx){
6555
(power_vector)[idx] = c->ambient/lyr[l].rz + power->cuboid[l][i][j];
6556
}
6557
else if((l == pcbidx) && model_secondary){
6558
(power_vector)[idx] = power->cuboid[l][i][j] + c->ambient/(model->config.r_convec_sec *
6559
(model->config.s_pcb * model->config.s_pcb) / (cw * ch));
6560
}
6561
else{
6562
(power_vector)[idx] = power->cuboid[l][i][j];
6563
}
6564
6565
if(model->layers[l].is_microchannel) {
6566
microchannel_config_t *uconf = model->layers[l].microchannel_config;
6567
6568
if(IS_INLET_CELL(uconf, i, j)) {
6569
double inlet_flow_rate = 0;
6570
6571
/* Add flow rates to other cells to determine inlet flow rate */
6572
6573
/* northern inlet*/
6574
if(i == 0) {
6575
// Check western cell
6576
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
6577
inlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
6578
}
6579
6580
// Check eastern cell
6581
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
6582
inlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
6583
}
6584
6585
// Check southern cell
6586
if(i < nr -1 && IS_FLUID_CELL(uconf, i+1, j)) {
6587
inlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
6588
}
6589
}
6590
6591
/* southern inlet */
6592
else if(i == nr - 1) {
6593
// Check western cell
6594
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
6595
inlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
6596
}
6597
6598
// Check eastern cell
6599
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
6600
inlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
6601
}
6602
6603
// Check northern cell
6604
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
6605
inlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
6606
}
6607
}
6608
6609
/* western inlet */
6610
else if(j == 0) {
6611
// Check eastern cell
6612
if(j < nc-1 && IS_FLUID_CELL(uconf, i, j+1)) {
6613
inlet_flow_rate += flow_rate(uconf, i, j+1, i, j);
6614
}
6615
6616
// Check northern cell
6617
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
6618
inlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
6619
}
6620
6621
// Check southern cell
6622
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
6623
inlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
6624
}
6625
}
6626
6627
/* eastern inlet */
6628
else if (j == nc - 1) {
6629
// Check western cell
6630
if(j > 0 && IS_FLUID_CELL(uconf, i, j-1)) {
6631
inlet_flow_rate += flow_rate(uconf, i, j-1, i, j);
6632
}
6633
6634
// Check northern cell
6635
if(i > 0 && IS_FLUID_CELL(uconf, i-1, j)) {
6636
inlet_flow_rate += flow_rate(uconf, i-1, j, i, j);
6637
}
6638
6639
// Check southern cell
6640
if(i < nr-1 && IS_FLUID_CELL(uconf, i+1, j)) {
6641
inlet_flow_rate += flow_rate(uconf, i+1, j, i, j);
6642
}
6643
}
6644
6645
// The inlet_flow_rate is negative because it is equal to all of the fluid flowing out of the inlet
6646
// Here we multiply by -1 to make it positive since it is in the power vector on the rhs of the equation
6647
//fprintf(stderr, "inlet_flow_rate BEFORE negation = %e\n", inlet_flow_rate);
6648
inlet_flow_rate *= -1;
6649
//fprintf(stderr, "inlet_flow_rate AFTER negation = %e\n", inlet_flow_rate);
6650
(power_vector)[idx] += uconf->coolant_capac * inlet_flow_rate * uconf->inlet_temperature;
6651
//fprintf(stderr, "Volumetric flow rate = %e m^3/s\n", inlet_flow_rate);
6652
//fprintf(stderr, "After inlets: power + %e = %e\n", uconf->coolant_capac * inlet_flow_rate * uconf->inlet_temperature, (*power_vector)[idx]);
6653
}
6654
}
6655
}
6656
}
6657
}
6658
6659
/* Package nodes */
6660
int base_idx = nl*nc*nr;
6661
(power_vector)[base_idx + SP_W] = 0;
6662
(power_vector)[base_idx + SP_E] = 0;
6663
(power_vector)[base_idx + SP_N] = 0;
6664
(power_vector)[base_idx + SP_S] = 0;
6665
(power_vector)[base_idx + SINK_C_W] = c->ambient/(pk->r_hs_c_per_x + pk->r_amb_c_per_x);
6666
(power_vector)[base_idx + SINK_C_E] = c->ambient/(pk->r_hs_c_per_x + pk->r_amb_c_per_x);
6667
(power_vector)[base_idx + SINK_C_N] = c->ambient/(pk->r_hs_c_per_y + pk->r_amb_c_per_y);
6668
(power_vector)[base_idx + SINK_C_S] = c->ambient/(pk->r_hs_c_per_y + pk->r_amb_c_per_y);
6669
(power_vector)[base_idx + SINK_W] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
6670
(power_vector)[base_idx + SINK_E] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
6671
(power_vector)[base_idx + SINK_N] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
6672
(power_vector)[base_idx + SINK_S] = c->ambient/(pk->r_hs_per + pk->r_amb_per);
6673
6674
if(model_secondary){
6675
(power_vector)[base_idx + SUB_W] = 0;
6676
(power_vector)[base_idx + SUB_E] = 0;
6677
(power_vector)[base_idx + SUB_N] = 0;
6678
(power_vector)[base_idx + SUB_S] = 0;
6679
(power_vector)[base_idx + SOLDER_W] = 0;
6680
(power_vector)[base_idx + SOLDER_E] = 0;
6681
(power_vector)[base_idx + SOLDER_N] = 0;
6682
(power_vector)[base_idx + SOLDER_S] = 0;
6683
(power_vector)[base_idx + PCB_C_W] = c->ambient/(pk->r_amb_sec_c_per_x);
6684
(power_vector)[base_idx + PCB_C_E] = c->ambient/(pk->r_amb_sec_c_per_x);
6685
(power_vector)[base_idx + PCB_C_N] = c->ambient/(pk->r_amb_sec_c_per_y);
6686
(power_vector)[base_idx + PCB_C_S] = c->ambient/(pk->r_amb_sec_c_per_y);
6687
(power_vector)[base_idx + PCB_W] = c->ambient/(pk->r_amb_sec_per);
6688
(power_vector)[base_idx + PCB_E] = c->ambient/(pk->r_amb_sec_per);
6689
(power_vector)[base_idx + PCB_N] = c->ambient/(pk->r_amb_sec_per);
6690
(power_vector)[base_idx + PCB_S] = c->ambient/(pk->r_amb_sec_per);
6691
}
6692
6693
return power_vector;
6694
}
6695
6696
diagonal_matrix_t *build_diagonal_matrix(grid_model_t *model)
6697
{
6698
package_RC_t *pk = &model->pack;
6699
int nr = model->rows;
6700
int nc = model->cols;
6701
int nl = model->n_layers;
6702
int m, l, i, j, idx;
6703
double *vals;
6704
6705
if(model->config.model_secondary)
6706
m = (nl*nc*nr + EXTRA + EXTRA_SEC);
6707
else
6708
m = (nl*nc*nr + EXTRA);
6709
6710
diagonal_matrix_t *diag_matrix = malloc(sizeof(diagonal_matrix_t));
6711
6712
if(!diag_matrix)
6713
fatal("Malloc failed to allocate space for diagonal matrix\n");
6714
6715
diag_matrix->n = m;
6716
6717
if ( !(diag_matrix->vals = doubleMalloc(m)) )
6718
fatal("Malloc fails for diagonal_matrix vals.\n");
6719
6720
for(l = 0; l < nl; l++) {
6721
for(i = 0; i < nr; i++) {
6722
for(j = 0; j < nc; j++) {
6723
idx = l*nr*nc + i*nc + j;
6724
6725
if(model->config.detailed_3D_used == 1) {
6726
diag_matrix->vals[idx] = find_cap_3D(l, i, j, model);
6727
}
6728
else {
6729
diag_matrix->vals[idx] = model->layers[l].c;
6730
}
6731
}
6732
}
6733
}
6734
6735
/* Package nodes */
6736
int base_idx = nl*nc*nr;
6737
diag_matrix->vals[base_idx + SP_W] = pk->c_sp_per_x;
6738
diag_matrix->vals[base_idx + SP_E] = pk->c_sp_per_x;
6739
diag_matrix->vals[base_idx + SP_N] = pk->c_sp_per_y;
6740
diag_matrix->vals[base_idx + SP_S] = pk->c_sp_per_y;
6741
diag_matrix->vals[base_idx + SINK_C_W] = pk->c_hs_c_per_x + pk->c_amb_c_per_x;
6742
diag_matrix->vals[base_idx + SINK_C_E] = pk->c_hs_c_per_x + pk->c_amb_c_per_x;
6743
diag_matrix->vals[base_idx + SINK_C_N] = pk->c_hs_c_per_y + pk->c_amb_c_per_y;
6744
diag_matrix->vals[base_idx + SINK_C_S] = pk->c_hs_c_per_y + pk->c_amb_c_per_y;
6745
diag_matrix->vals[base_idx + SINK_W] = pk->c_hs_per + pk->c_amb_per;
6746
diag_matrix->vals[base_idx + SINK_E] = pk->c_hs_per + pk->c_amb_per;
6747
diag_matrix->vals[base_idx + SINK_N] = pk->c_hs_per + pk->c_amb_per;
6748
diag_matrix->vals[base_idx + SINK_S] = pk->c_hs_per + pk->c_amb_per;
6749
6750
/* SECONDARY MODELING NOT IMPLEMENTED YET */
6751
if(model->config.model_secondary){
6752
diag_matrix->vals[base_idx + SUB_W] = 0;
6753
diag_matrix->vals[base_idx + SUB_E] = 0;
6754
diag_matrix->vals[base_idx + SUB_N] = 0;
6755
diag_matrix->vals[base_idx + SUB_S] = 0;
6756
diag_matrix->vals[base_idx + SOLDER_W] = 0;
6757
diag_matrix->vals[base_idx + SOLDER_E] = 0;
6758
diag_matrix->vals[base_idx + SOLDER_N] = 0;
6759
diag_matrix->vals[base_idx + SOLDER_S] = 0;
6760
diag_matrix->vals[base_idx + PCB_C_W] = 0;
6761
diag_matrix->vals[base_idx + PCB_C_E] = 0;
6762
diag_matrix->vals[base_idx + PCB_C_N] = 0;
6763
diag_matrix->vals[base_idx + PCB_C_S] = 0;
6764
diag_matrix->vals[base_idx + PCB_W] = 0;
6765
diag_matrix->vals[base_idx + PCB_E] = 0;
6766
diag_matrix->vals[base_idx + PCB_N] = 0;
6767
diag_matrix->vals[base_idx + PCB_S] = 0;
6768
}
6769
6770
//for(i = 0; i < diag_matrix->n; i++)
6771
// fprintf(stderr, "capacitance[%d] = %e\n", i, diag_matrix->vals[i]);
6772
6773
if(MAKE_CSVS)
6774
diagTocsv("C.csv", diag_matrix);
6775
6776
return diag_matrix;
6777
}
6778
#endif // SUPERLU > 0
6779
6780