epyt-flow 0.14.1__py3-none-any.whl → 0.15.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- epyt_flow/VERSION +1 -1
- epyt_flow/__init__.py +0 -37
- epyt_flow/data/benchmarks/battledim.py +2 -2
- epyt_flow/data/benchmarks/leakdb.py +12 -9
- epyt_flow/gym/scenario_control_env.py +32 -33
- epyt_flow/simulation/events/actuator_events.py +24 -18
- epyt_flow/simulation/events/leakages.py +59 -57
- epyt_flow/simulation/events/quality_events.py +21 -30
- epyt_flow/simulation/events/system_event.py +3 -3
- epyt_flow/simulation/scada/complex_control.py +14 -12
- epyt_flow/simulation/scada/custom_control.py +22 -21
- epyt_flow/simulation/scada/scada_data.py +108 -105
- epyt_flow/simulation/scada/simple_control.py +38 -31
- epyt_flow/simulation/scenario_simulator.py +368 -395
- epyt_flow/simulation/sensor_config.py +31 -32
- epyt_flow/topology.py +11 -10
- epyt_flow/uncertainty/model_uncertainty.py +146 -122
- epyt_flow/utils.py +66 -0
- epyt_flow/visualization/visualization_utils.py +4 -2
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/METADATA +14 -19
- epyt_flow-0.15.0.dist-info/RECORD +65 -0
- epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -60
- epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -21
- epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -151
- epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -5930
- epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -961
- epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -79
- epyt_flow/EPANET/EPANET/SRC_engines/flowbalance.c +0 -186
- epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -219
- epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -1000
- epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -177
- epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -28
- epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -1303
- epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -1172
- epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -781
- epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -442
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -464
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -1960
- epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -518
- epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -884
- epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -672
- epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -735
- epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -2265
- epyt_flow/EPANET/EPANET/SRC_engines/leakage.c +0 -527
- epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -146
- epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -24
- epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -853
- epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -1691
- epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -695
- epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -800
- epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -696
- epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -1557
- epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -1500
- epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -871
- epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -508
- epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -928
- epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.c +0 -59
- epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.h +0 -38
- epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.c +0 -92
- epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.h +0 -39
- epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.c +0 -212
- epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.h +0 -81
- epyt_flow/EPANET/EPANET/SRC_engines/validate.c +0 -408
- epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -53
- epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -27
- epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -107
- epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -28
- epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -102
- epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -42
- epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -937
- epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -39
- epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -204
- epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -24
- epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -1285
- epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -368
- epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -42
- epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -586
- epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -116
- epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -260
- epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -175
- epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -35
- epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -1504
- epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -401
- epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -791
- epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -2010
- epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -400
- epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -422
- epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -1164
- epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -551
- epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -524
- epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -56
- epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -158
- epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -34
- epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -287
- epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -39
- epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -293
- epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -35
- epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -816
- epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -29
- epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -14
- epyt_flow/EPANET/compile_linux.sh +0 -4
- epyt_flow/EPANET/compile_macos.sh +0 -4
- epyt_flow/simulation/backend/__init__.py +0 -1
- epyt_flow/simulation/backend/my_epyt.py +0 -1101
- epyt_flow-0.14.1.dist-info/RECORD +0 -148
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/WHEEL +0 -0
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/licenses/LICENSE +0 -0
- {epyt_flow-0.14.1.dist-info → epyt_flow-0.15.0.dist-info}/top_level.txt +0 -0
|
@@ -1,871 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
******************************************************************************
|
|
3
|
-
Project: OWA EPANET
|
|
4
|
-
Version: 2.3
|
|
5
|
-
Module: smatrix.c
|
|
6
|
-
Description: solves a sparse set of linear equations
|
|
7
|
-
Authors: see AUTHORS
|
|
8
|
-
Copyright: see AUTHORS
|
|
9
|
-
License: see LICENSE
|
|
10
|
-
Last Updated: 05/15/2019
|
|
11
|
-
******************************************************************************
|
|
12
|
-
*/
|
|
13
|
-
/*
|
|
14
|
-
This module contains the sparse matrix routines used to solve a network's
|
|
15
|
-
hydraulic equations. The functions exported by this module are:
|
|
16
|
-
createsparse() -- called from openhyd() in HYDRAUL.C
|
|
17
|
-
freesparse() -- called from closehyd() in HYDRAUL.C
|
|
18
|
-
linsolve() -- called from netsolve() in HYDRAUL.C
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
#include <stdlib.h>
|
|
22
|
-
#include <stdio.h>
|
|
23
|
-
#include <string.h>
|
|
24
|
-
#include <math.h>
|
|
25
|
-
#include <limits.h>
|
|
26
|
-
|
|
27
|
-
#include <time.h> //For optional timer macros
|
|
28
|
-
|
|
29
|
-
#include "text.h"
|
|
30
|
-
#include "types.h"
|
|
31
|
-
#include "funcs.h"
|
|
32
|
-
|
|
33
|
-
// The multiple minimum degree re-ordering routine (see genmmd.c)
|
|
34
|
-
extern int genmmd(int *neqns, int *xadj, int *adjncy, int *invp, int *perm,
|
|
35
|
-
int *delta, int *dhead, int *qsize, int *llist, int *marker,
|
|
36
|
-
int *maxint, int *nofsub);
|
|
37
|
-
|
|
38
|
-
// Exported functions
|
|
39
|
-
int createsparse(Project *);
|
|
40
|
-
void freesparse(Project *);
|
|
41
|
-
int linsolve(Smatrix *, int);
|
|
42
|
-
|
|
43
|
-
// Local functions
|
|
44
|
-
static int allocsmatrix(Smatrix *, int, int);
|
|
45
|
-
static int alloclinsolve(Smatrix *, int);
|
|
46
|
-
static int localadjlists(Network *, Smatrix *);
|
|
47
|
-
static int paralink(Network *, Smatrix *, int, int, int k);
|
|
48
|
-
static void xparalinks(Network *);
|
|
49
|
-
static int reordernodes(Project *);
|
|
50
|
-
static int factorize(Project *);
|
|
51
|
-
static int growlist(Project *, int, int *);
|
|
52
|
-
static int newlink(Project *, Padjlist, int *);
|
|
53
|
-
static int linked(Network *, int, int);
|
|
54
|
-
static int addlink(Network *, int, int, int);
|
|
55
|
-
static int storesparse(Project *, int);
|
|
56
|
-
static int sortsparse(Smatrix *, int);
|
|
57
|
-
static void transpose(int, int *, int *, int *, int *,
|
|
58
|
-
int *, int *, int *);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
/*************************************************************************
|
|
62
|
-
* Timer macros
|
|
63
|
-
**************************************************************************/
|
|
64
|
-
//#define cleartimer(tmr) (tmr = 0.0)
|
|
65
|
-
//#define starttimer(tmr) (tmr -= ((double) clock()/CLOCKS_PER_SEC));
|
|
66
|
-
//#define stoptimer(tmr) (tmr += ((double) clock()/CLOCKS_PER_SEC));
|
|
67
|
-
//#define gettimer(tmr) (tmr)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
/*************************************************************************
|
|
71
|
-
* The following data type implements a timer
|
|
72
|
-
**************************************************************************/
|
|
73
|
-
// typedef double timer;
|
|
74
|
-
// timer SmatrixTimer;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
int createsparse(Project *pr)
|
|
78
|
-
/*
|
|
79
|
-
**--------------------------------------------------------------
|
|
80
|
-
** Input: none
|
|
81
|
-
** Output: returns error code
|
|
82
|
-
** Purpose: creates sparse representation of coeff. matrix
|
|
83
|
-
**--------------------------------------------------------------
|
|
84
|
-
*/
|
|
85
|
-
{
|
|
86
|
-
Network *net = &pr->network;
|
|
87
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
88
|
-
|
|
89
|
-
int errcode = 0;
|
|
90
|
-
|
|
91
|
-
// cleartimer(SmatrixTimer);
|
|
92
|
-
// starttimer(SmatrixTimer);
|
|
93
|
-
|
|
94
|
-
// Allocate sparse matrix data structures
|
|
95
|
-
errcode = allocsmatrix(sm, net->Nnodes, net->Nlinks);
|
|
96
|
-
if (errcode) return errcode;
|
|
97
|
-
|
|
98
|
-
// Build a local version of node-link adjacency lists
|
|
99
|
-
// with parallel links removed
|
|
100
|
-
errcode = localadjlists(net, sm);
|
|
101
|
-
if (errcode) return errcode;
|
|
102
|
-
|
|
103
|
-
// Re-order nodes to minimize number of non-zero coeffs.
|
|
104
|
-
// in factorized solution matrix
|
|
105
|
-
ERRCODE(reordernodes(pr));
|
|
106
|
-
|
|
107
|
-
// Factorize solution matrix by updating adjacency lists
|
|
108
|
-
// with non-zero connections due to fill-ins
|
|
109
|
-
sm->Ncoeffs = net->Nlinks;
|
|
110
|
-
ERRCODE(factorize(pr));
|
|
111
|
-
|
|
112
|
-
// Allocate memory for sparse storage of positions of non-zero
|
|
113
|
-
// coeffs. and store these positions in vector NZSUB
|
|
114
|
-
ERRCODE(storesparse(pr, net->Njuncs));
|
|
115
|
-
|
|
116
|
-
// Free memory used for local adjacency lists and sort
|
|
117
|
-
// row indexes in NZSUB to optimize linsolve()
|
|
118
|
-
freeadjlists(net);
|
|
119
|
-
ERRCODE(sortsparse(sm, net->Njuncs));
|
|
120
|
-
|
|
121
|
-
// Allocate memory used by linear eqn. solver
|
|
122
|
-
ERRCODE(alloclinsolve(sm, net->Nnodes));
|
|
123
|
-
|
|
124
|
-
// Re-build adjacency lists for future use
|
|
125
|
-
ERRCODE(buildadjlists(net));
|
|
126
|
-
return errcode;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
int allocsmatrix(Smatrix *sm, int Nnodes, int Nlinks)
|
|
131
|
-
/*
|
|
132
|
-
**--------------------------------------------------------------
|
|
133
|
-
** Input: none
|
|
134
|
-
** Output: returns error code
|
|
135
|
-
** Purpose: allocates memory for representing a sparse matrix
|
|
136
|
-
**--------------------------------------------------------------
|
|
137
|
-
*/
|
|
138
|
-
{
|
|
139
|
-
int errcode = 0;
|
|
140
|
-
|
|
141
|
-
// Memory for linear eqn. solver allocated in alloclinsolve().
|
|
142
|
-
sm->Aij = NULL;
|
|
143
|
-
sm->Aii = NULL;
|
|
144
|
-
sm->F = NULL;
|
|
145
|
-
sm->temp = NULL;
|
|
146
|
-
sm->link = NULL;
|
|
147
|
-
sm->first = NULL;
|
|
148
|
-
|
|
149
|
-
// Memory for representing sparse matrix data structure
|
|
150
|
-
sm->Order = (int *) calloc(Nnodes+1, sizeof(int));
|
|
151
|
-
sm->Row = (int *) calloc(Nnodes+1, sizeof(int));
|
|
152
|
-
sm->Ndx = (int *) calloc(Nlinks+1, sizeof(int));
|
|
153
|
-
ERRCODE(MEMCHECK(sm->Order));
|
|
154
|
-
ERRCODE(MEMCHECK(sm->Row));
|
|
155
|
-
ERRCODE(MEMCHECK(sm->Ndx));
|
|
156
|
-
return errcode;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
int alloclinsolve(Smatrix *sm, int n)
|
|
161
|
-
/*
|
|
162
|
-
**--------------------------------------------------------------
|
|
163
|
-
** Input: none
|
|
164
|
-
** Output: returns error code
|
|
165
|
-
** Purpose: allocates memory used by linear eqn. solver.
|
|
166
|
-
**--------------------------------------------------------------
|
|
167
|
-
*/
|
|
168
|
-
{
|
|
169
|
-
int errcode = 0;
|
|
170
|
-
n = n + 1; // All arrays are 1-based
|
|
171
|
-
|
|
172
|
-
sm->Aij = (double *)calloc(sm->Ncoeffs + 1, sizeof(double));
|
|
173
|
-
sm->Aii = (double *)calloc(n, sizeof(double));
|
|
174
|
-
sm->F = (double *)calloc(n, sizeof(double));
|
|
175
|
-
sm->temp = (double *)calloc(n, sizeof(double));
|
|
176
|
-
sm->link = (int *)calloc(n, sizeof(int));
|
|
177
|
-
sm->first = (int *)calloc(n, sizeof(int));
|
|
178
|
-
ERRCODE(MEMCHECK(sm->Aij));
|
|
179
|
-
ERRCODE(MEMCHECK(sm->Aii));
|
|
180
|
-
ERRCODE(MEMCHECK(sm->F));
|
|
181
|
-
ERRCODE(MEMCHECK(sm->temp));
|
|
182
|
-
ERRCODE(MEMCHECK(sm->link));
|
|
183
|
-
ERRCODE(MEMCHECK(sm->first));
|
|
184
|
-
return errcode;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
void freesparse(Project *pr)
|
|
189
|
-
/*
|
|
190
|
-
**----------------------------------------------------------------
|
|
191
|
-
** Input: None
|
|
192
|
-
** Output: None
|
|
193
|
-
** Purpose: Frees memory used for sparse matrix storage
|
|
194
|
-
**----------------------------------------------------------------
|
|
195
|
-
*/
|
|
196
|
-
{
|
|
197
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
198
|
-
|
|
199
|
-
// stoptimer(SmatrixTimer);
|
|
200
|
-
// printf("\n");
|
|
201
|
-
// printf("\n Processing Time = %7.3f s", gettimer(SmatrixTimer));
|
|
202
|
-
// printf("\n");
|
|
203
|
-
|
|
204
|
-
FREE(sm->Order);
|
|
205
|
-
FREE(sm->Row);
|
|
206
|
-
FREE(sm->Ndx);
|
|
207
|
-
FREE(sm->XLNZ);
|
|
208
|
-
FREE(sm->NZSUB);
|
|
209
|
-
FREE(sm->LNZ);
|
|
210
|
-
|
|
211
|
-
FREE(sm->Aij);
|
|
212
|
-
FREE(sm->Aii);
|
|
213
|
-
FREE(sm->F);
|
|
214
|
-
FREE(sm->temp);
|
|
215
|
-
FREE(sm->link);
|
|
216
|
-
FREE(sm->first);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
int localadjlists(Network *net, Smatrix *sm)
|
|
221
|
-
/*
|
|
222
|
-
**--------------------------------------------------------------
|
|
223
|
-
** Input: none
|
|
224
|
-
** Output: returns error code
|
|
225
|
-
** Purpose: builds linked list of non-parallel links adjacent to each node
|
|
226
|
-
**--------------------------------------------------------------
|
|
227
|
-
*/
|
|
228
|
-
{
|
|
229
|
-
int i, j, k;
|
|
230
|
-
int pmark = 0; // parallel link marker
|
|
231
|
-
int errcode = 0;
|
|
232
|
-
Padjlist alink;
|
|
233
|
-
|
|
234
|
-
// Create an array of adjacency lists
|
|
235
|
-
freeadjlists(net);
|
|
236
|
-
net->Adjlist = (Padjlist *)calloc(net->Nnodes + 1, sizeof(Padjlist));
|
|
237
|
-
if (net->Adjlist == NULL) return 101;
|
|
238
|
-
|
|
239
|
-
// For each link, update adjacency lists of its end nodes
|
|
240
|
-
for (k = 1; k <= net->Nlinks; k++)
|
|
241
|
-
{
|
|
242
|
-
i = net->Link[k].N1;
|
|
243
|
-
j = net->Link[k].N2;
|
|
244
|
-
pmark = paralink(net, sm, i, j, k); // Parallel link check
|
|
245
|
-
|
|
246
|
-
// Include link in start node i's list
|
|
247
|
-
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
|
248
|
-
if (alink == NULL) return(101);
|
|
249
|
-
if (!pmark) alink->node = j;
|
|
250
|
-
else alink->node = 0; // Parallel link marker
|
|
251
|
-
alink->link = k;
|
|
252
|
-
alink->next = net->Adjlist[i];
|
|
253
|
-
net->Adjlist[i] = alink;
|
|
254
|
-
|
|
255
|
-
// Include link in end node j's list
|
|
256
|
-
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
|
257
|
-
if (alink == NULL) return(101);
|
|
258
|
-
if (!pmark) alink->node = i;
|
|
259
|
-
else alink->node = 0; // Parallel link marker
|
|
260
|
-
alink->link = k;
|
|
261
|
-
alink->next = net->Adjlist[j];
|
|
262
|
-
net->Adjlist[j] = alink;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Remove parallel links from adjacency lists
|
|
266
|
-
xparalinks(net);
|
|
267
|
-
return errcode;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
int paralink(Network *net, Smatrix *sm, int i, int j, int k)
|
|
272
|
-
/*
|
|
273
|
-
**--------------------------------------------------------------
|
|
274
|
-
** Input: i = index of start node of link
|
|
275
|
-
** j = index of end node of link
|
|
276
|
-
** k = link index
|
|
277
|
-
** Output: returns 1 if link k parallels another link, else 0
|
|
278
|
-
** Purpose: checks for parallel links between nodes i and j
|
|
279
|
-
**
|
|
280
|
-
**--------------------------------------------------------------
|
|
281
|
-
*/
|
|
282
|
-
{
|
|
283
|
-
Padjlist alink;
|
|
284
|
-
for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next)
|
|
285
|
-
{
|
|
286
|
-
// Link || to k (same end nodes)
|
|
287
|
-
if (alink->node == j)
|
|
288
|
-
{
|
|
289
|
-
// Assign Ndx entry to this link
|
|
290
|
-
sm->Ndx[k] = alink->link;
|
|
291
|
-
return(1);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
// Ndx entry if link not parallel
|
|
295
|
-
sm->Ndx[k] = k;
|
|
296
|
-
return(0);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
void xparalinks(Network *net)
|
|
301
|
-
/*
|
|
302
|
-
**--------------------------------------------------------------
|
|
303
|
-
** Input: none
|
|
304
|
-
** Output: none
|
|
305
|
-
** Purpose: removes parallel links from nodal adjacency lists
|
|
306
|
-
**--------------------------------------------------------------
|
|
307
|
-
*/
|
|
308
|
-
{
|
|
309
|
-
int i;
|
|
310
|
-
Padjlist alink, // Current item in adjacency list
|
|
311
|
-
blink; // Previous item in adjacency list
|
|
312
|
-
|
|
313
|
-
// Scan adjacency list of each node
|
|
314
|
-
for (i = 1; i <= net->Nnodes; i++)
|
|
315
|
-
{
|
|
316
|
-
alink = net->Adjlist[i]; // First item in list
|
|
317
|
-
blink = NULL;
|
|
318
|
-
while (alink != NULL)
|
|
319
|
-
{
|
|
320
|
-
if (alink->node == 0) // Parallel link marker found
|
|
321
|
-
{
|
|
322
|
-
if (blink == NULL) // This holds at start of list
|
|
323
|
-
{
|
|
324
|
-
net->Adjlist[i] = alink->next;
|
|
325
|
-
free(alink); // Remove item from list
|
|
326
|
-
alink = net->Adjlist[i];
|
|
327
|
-
}
|
|
328
|
-
else // This holds for interior of list
|
|
329
|
-
{
|
|
330
|
-
blink->next = alink->next;
|
|
331
|
-
free(alink); // Remove item from list
|
|
332
|
-
alink = blink->next;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
else
|
|
336
|
-
{
|
|
337
|
-
blink = alink; // Move to next item in list
|
|
338
|
-
alink = alink->next;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
int reordernodes(Project *pr)
|
|
346
|
-
/*
|
|
347
|
-
**--------------------------------------------------------------
|
|
348
|
-
** Input: none
|
|
349
|
-
** Output: returns 1 if successful, 0 if not
|
|
350
|
-
** Purpose: re-orders nodes to minimize # of non-zeros that
|
|
351
|
-
** will appear in factorized solution matrix
|
|
352
|
-
**--------------------------------------------------------------
|
|
353
|
-
*/
|
|
354
|
-
{
|
|
355
|
-
Network *net = &pr->network;
|
|
356
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
357
|
-
|
|
358
|
-
int k, knode, m, njuncs, nlinks;
|
|
359
|
-
int delta = -1;
|
|
360
|
-
int nofsub = 0;
|
|
361
|
-
int maxint = INT_MAX; //defined in limits.h
|
|
362
|
-
int errcode;
|
|
363
|
-
Padjlist alink;
|
|
364
|
-
|
|
365
|
-
// Local versions of node adjacency lists
|
|
366
|
-
int *adjncy = NULL;
|
|
367
|
-
int *xadj = NULL;
|
|
368
|
-
|
|
369
|
-
// Work arrays
|
|
370
|
-
int *dhead = NULL;
|
|
371
|
-
int *qsize = NULL;
|
|
372
|
-
int *llist = NULL;
|
|
373
|
-
int *marker = NULL;
|
|
374
|
-
|
|
375
|
-
// Default ordering
|
|
376
|
-
for (k = 1; k <= net->Nnodes; k++)
|
|
377
|
-
{
|
|
378
|
-
sm->Row[k] = k;
|
|
379
|
-
sm->Order[k] = k;
|
|
380
|
-
}
|
|
381
|
-
njuncs = net->Njuncs;
|
|
382
|
-
nlinks = net->Nlinks;
|
|
383
|
-
|
|
384
|
-
// Allocate memory
|
|
385
|
-
adjncy = (int *) calloc(2*nlinks+1, sizeof(int));
|
|
386
|
-
xadj = (int *) calloc(njuncs+2, sizeof(int));
|
|
387
|
-
dhead = (int *) calloc(njuncs+1, sizeof(int));
|
|
388
|
-
qsize = (int *) calloc(njuncs + 1, sizeof(int));
|
|
389
|
-
llist = (int *) calloc(njuncs + 1, sizeof(int));
|
|
390
|
-
marker = (int *) calloc(njuncs + 1, sizeof(int));
|
|
391
|
-
if (adjncy && xadj && dhead && qsize && llist && marker)
|
|
392
|
-
{
|
|
393
|
-
// Create local versions of node adjacency lists
|
|
394
|
-
xadj[1] = 1;
|
|
395
|
-
m = 1;
|
|
396
|
-
for (k = 1; k <= njuncs; k++)
|
|
397
|
-
{
|
|
398
|
-
for (alink = net->Adjlist[k]; alink != NULL; alink = alink->next)
|
|
399
|
-
{
|
|
400
|
-
knode = alink->node;
|
|
401
|
-
if (knode > 0 && knode <= njuncs)
|
|
402
|
-
{
|
|
403
|
-
adjncy[m] = knode;
|
|
404
|
-
m++;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
xadj[k+1] = m;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Generate a multiple minimum degree node re-ordering
|
|
411
|
-
genmmd(&njuncs, xadj, adjncy, sm->Row, sm->Order, &delta,
|
|
412
|
-
dhead, qsize, llist, marker, &maxint, &nofsub);
|
|
413
|
-
errcode = 0;
|
|
414
|
-
}
|
|
415
|
-
else errcode = 101; //insufficient memory
|
|
416
|
-
|
|
417
|
-
// Free memory
|
|
418
|
-
FREE(adjncy);
|
|
419
|
-
FREE(xadj);
|
|
420
|
-
FREE(dhead);
|
|
421
|
-
FREE(qsize);
|
|
422
|
-
FREE(llist);
|
|
423
|
-
FREE(marker);
|
|
424
|
-
return errcode;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
int factorize(Project *pr)
|
|
429
|
-
/*
|
|
430
|
-
**--------------------------------------------------------------
|
|
431
|
-
** Input: none
|
|
432
|
-
** Output: returns error code
|
|
433
|
-
** Purpose: symbolically factorizes the solution matrix in
|
|
434
|
-
** terms of its adjacency lists
|
|
435
|
-
**--------------------------------------------------------------
|
|
436
|
-
*/
|
|
437
|
-
{
|
|
438
|
-
Network *net = &pr->network;
|
|
439
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
440
|
-
|
|
441
|
-
int k, knode;
|
|
442
|
-
int errcode = 0;
|
|
443
|
-
Padjlist alink;
|
|
444
|
-
|
|
445
|
-
// Find degree of each junction node
|
|
446
|
-
int *degree = (int *)calloc(net->Nnodes + 1, sizeof(int));
|
|
447
|
-
if (degree == NULL) return 101;
|
|
448
|
-
|
|
449
|
-
// NOTE: For purposes of node re-ordering, Tanks (nodes with
|
|
450
|
-
// indexes above Njuncs) have zero degree of adjacency.
|
|
451
|
-
|
|
452
|
-
for (k = 1; k <= net->Njuncs; k++)
|
|
453
|
-
{
|
|
454
|
-
for (alink = net->Adjlist[k]; alink != NULL; alink = alink->next)
|
|
455
|
-
{
|
|
456
|
-
if (alink->node > 0) degree[k]++;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// Augment each junction's adjacency list to account for
|
|
461
|
-
// new connections created when solution matrix is solved.
|
|
462
|
-
// NOTE: Only junctions (indexes <= Njuncs) appear in solution matrix.
|
|
463
|
-
for (k = 1; k <= net->Njuncs; k++) // Examine each junction
|
|
464
|
-
{
|
|
465
|
-
knode = sm->Order[k]; // Re-ordered index
|
|
466
|
-
if (!growlist(pr, knode, degree)) // Augment adjacency list
|
|
467
|
-
{
|
|
468
|
-
errcode = 101;
|
|
469
|
-
break;
|
|
470
|
-
}
|
|
471
|
-
degree[knode] = 0; // In-activate node
|
|
472
|
-
}
|
|
473
|
-
free(degree);
|
|
474
|
-
return errcode;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
int growlist(Project *pr, int knode, int *degree)
|
|
479
|
-
/*
|
|
480
|
-
**--------------------------------------------------------------
|
|
481
|
-
** Input: knode = node index
|
|
482
|
-
** Output: returns 1 if successful, 0 if not
|
|
483
|
-
** Purpose: creates new entries in knode's adjacency list for
|
|
484
|
-
** all unlinked pairs of active nodes that are
|
|
485
|
-
** adjacent to knode
|
|
486
|
-
**--------------------------------------------------------------
|
|
487
|
-
*/
|
|
488
|
-
{
|
|
489
|
-
Network *net = &pr->network;
|
|
490
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
491
|
-
|
|
492
|
-
int node;
|
|
493
|
-
Padjlist alink;
|
|
494
|
-
|
|
495
|
-
// Iterate through all nodes connected to knode
|
|
496
|
-
for (alink = net->Adjlist[knode]; alink != NULL; alink = alink -> next)
|
|
497
|
-
{
|
|
498
|
-
node = alink->node; // End node of connecting link
|
|
499
|
-
if (node > 0 && degree[node] > 0) // End node is active
|
|
500
|
-
{
|
|
501
|
-
degree[node]--; // Reduce degree of adjacency
|
|
502
|
-
if (!newlink(pr, alink, degree)) // Add to adjacency list
|
|
503
|
-
{
|
|
504
|
-
return 0;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return 1;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
int newlink(Project *pr, Padjlist alink, int *degree)
|
|
513
|
-
/*
|
|
514
|
-
**--------------------------------------------------------------
|
|
515
|
-
** Input: alink = element of node's adjacency list
|
|
516
|
-
** Output: returns 1 if successful, 0 if not
|
|
517
|
-
** Purpose: links end of current adjacent link to end nodes of
|
|
518
|
-
** all links that follow it on adjacency list
|
|
519
|
-
**--------------------------------------------------------------
|
|
520
|
-
*/
|
|
521
|
-
{
|
|
522
|
-
Network *net = &pr->network;
|
|
523
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
524
|
-
|
|
525
|
-
int inode, jnode;
|
|
526
|
-
Padjlist blink;
|
|
527
|
-
|
|
528
|
-
// Scan all entries in adjacency list that follow anode.
|
|
529
|
-
inode = alink->node; // End node of connection to anode
|
|
530
|
-
for (blink = alink->next; blink != NULL; blink = blink->next)
|
|
531
|
-
{
|
|
532
|
-
jnode = blink->node; // End node of next connection
|
|
533
|
-
|
|
534
|
-
// If jnode still active, and inode not connected to jnode,
|
|
535
|
-
// then add a new connection between inode and jnode.
|
|
536
|
-
if (jnode > 0 && degree[jnode] > 0) // jnode still active
|
|
537
|
-
{
|
|
538
|
-
if (!linked(net, inode, jnode)) // inode not linked to jnode
|
|
539
|
-
{
|
|
540
|
-
// Since new connection represents a non-zero coeff.
|
|
541
|
-
// in the solution matrix, update the coeff. count.
|
|
542
|
-
sm->Ncoeffs++;
|
|
543
|
-
|
|
544
|
-
// Update adjacency lists for inode & jnode to
|
|
545
|
-
// reflect the new connection.
|
|
546
|
-
if (!addlink(net, inode, jnode, sm->Ncoeffs)) return 0;
|
|
547
|
-
if (!addlink(net, jnode, inode, sm->Ncoeffs)) return 0;
|
|
548
|
-
degree[inode]++;
|
|
549
|
-
degree[jnode]++;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
return 1;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
int linked(Network *net, int i, int j)
|
|
558
|
-
/*
|
|
559
|
-
**--------------------------------------------------------------
|
|
560
|
-
** Input: i = node index
|
|
561
|
-
** j = node index
|
|
562
|
-
** Output: returns 1 if nodes i and j are linked, 0 if not
|
|
563
|
-
** Purpose: checks if nodes i and j are already linked.
|
|
564
|
-
**--------------------------------------------------------------
|
|
565
|
-
*/
|
|
566
|
-
{
|
|
567
|
-
Padjlist alink;
|
|
568
|
-
for (alink = net->Adjlist[i]; alink != NULL; alink = alink->next)
|
|
569
|
-
{
|
|
570
|
-
if (alink->node == j) return 1;
|
|
571
|
-
}
|
|
572
|
-
return 0;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
int addlink(Network *net, int i, int j, int n)
|
|
577
|
-
/*
|
|
578
|
-
**--------------------------------------------------------------
|
|
579
|
-
** Input: i = node index
|
|
580
|
-
** j = node index
|
|
581
|
-
** n = link index
|
|
582
|
-
** Output: returns 1 if successful, 0 if not
|
|
583
|
-
** Purpose: augments node i's adjacency list with node j
|
|
584
|
-
**--------------------------------------------------------------
|
|
585
|
-
*/
|
|
586
|
-
{
|
|
587
|
-
Padjlist alink;
|
|
588
|
-
alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist));
|
|
589
|
-
if (alink == NULL) return 0;
|
|
590
|
-
alink->node = j;
|
|
591
|
-
alink->link = n;
|
|
592
|
-
alink->next = net->Adjlist[i];
|
|
593
|
-
net->Adjlist[i] = alink;
|
|
594
|
-
return 1;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
int storesparse(Project *pr, int n)
|
|
599
|
-
/*
|
|
600
|
-
**--------------------------------------------------------------
|
|
601
|
-
** Input: n = number of rows in solution matrix
|
|
602
|
-
** Output: returns error code
|
|
603
|
-
** Purpose: stores row indexes of non-zeros of each column of
|
|
604
|
-
** lower triangular portion of factorized matrix
|
|
605
|
-
**--------------------------------------------------------------
|
|
606
|
-
*/
|
|
607
|
-
{
|
|
608
|
-
Network *net = &pr->network;
|
|
609
|
-
Smatrix *sm = &pr->hydraul.smatrix;
|
|
610
|
-
|
|
611
|
-
int i, ii, j, k, l, m;
|
|
612
|
-
int errcode = 0;
|
|
613
|
-
Padjlist alink;
|
|
614
|
-
|
|
615
|
-
// Allocate sparse matrix storage
|
|
616
|
-
sm->XLNZ = (int *) calloc(n+2, sizeof(int));
|
|
617
|
-
sm->NZSUB = (int *) calloc(sm->Ncoeffs+2, sizeof(int));
|
|
618
|
-
sm->LNZ = (int *) calloc(sm->Ncoeffs+2, sizeof(int));
|
|
619
|
-
ERRCODE(MEMCHECK(sm->XLNZ));
|
|
620
|
-
ERRCODE(MEMCHECK(sm->NZSUB));
|
|
621
|
-
ERRCODE(MEMCHECK(sm->LNZ));
|
|
622
|
-
if (errcode) return errcode;
|
|
623
|
-
|
|
624
|
-
// Generate row index pointers for each column of matrix
|
|
625
|
-
k = 0;
|
|
626
|
-
sm->XLNZ[1] = 1;
|
|
627
|
-
for (i = 1; i <= n; i++) // column
|
|
628
|
-
{
|
|
629
|
-
m = 0;
|
|
630
|
-
ii = sm->Order[i];
|
|
631
|
-
for (alink = net->Adjlist[ii]; alink != NULL; alink = alink->next)
|
|
632
|
-
{
|
|
633
|
-
if (alink->node == 0) continue;
|
|
634
|
-
j = sm->Row[alink->node]; // row
|
|
635
|
-
l = alink->link;
|
|
636
|
-
if (j > i && j <= n)
|
|
637
|
-
{
|
|
638
|
-
m++;
|
|
639
|
-
k++;
|
|
640
|
-
sm->NZSUB[k] = j;
|
|
641
|
-
sm->LNZ[k] = l;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
sm->XLNZ[i+1] = sm->XLNZ[i] + m;
|
|
645
|
-
}
|
|
646
|
-
return errcode;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
int sortsparse(Smatrix *sm, int n)
|
|
651
|
-
/*
|
|
652
|
-
**--------------------------------------------------------------
|
|
653
|
-
** Input: n = number of rows in solution matrix
|
|
654
|
-
** Output: returns error code
|
|
655
|
-
** Purpose: puts row indexes in ascending order in NZSUB
|
|
656
|
-
**--------------------------------------------------------------
|
|
657
|
-
*/
|
|
658
|
-
{
|
|
659
|
-
int i, k;
|
|
660
|
-
int *xlnzt, *nzsubt, *lnzt, *nzt;
|
|
661
|
-
int errcode = 0;
|
|
662
|
-
|
|
663
|
-
int *LNZ = sm->LNZ;
|
|
664
|
-
int *XLNZ = sm->XLNZ;
|
|
665
|
-
int *NZSUB = sm->NZSUB;
|
|
666
|
-
|
|
667
|
-
xlnzt = (int *) calloc(n+2, sizeof(int));
|
|
668
|
-
nzsubt = (int *) calloc(sm->Ncoeffs+2, sizeof(int));
|
|
669
|
-
lnzt = (int *) calloc(sm->Ncoeffs+2, sizeof(int));
|
|
670
|
-
nzt = (int *) calloc(n+2, sizeof(int));
|
|
671
|
-
ERRCODE(MEMCHECK(xlnzt));
|
|
672
|
-
ERRCODE(MEMCHECK(nzsubt));
|
|
673
|
-
ERRCODE(MEMCHECK(lnzt));
|
|
674
|
-
ERRCODE(MEMCHECK(nzt));
|
|
675
|
-
if (!errcode)
|
|
676
|
-
{
|
|
677
|
-
// Count # non-zeros in each row
|
|
678
|
-
for (i = 1; i <= n; i++) nzt[i] = 0;
|
|
679
|
-
for (i = 1; i <= n; i++)
|
|
680
|
-
{
|
|
681
|
-
for (k = XLNZ[i]; k < XLNZ[i+1]; k++) nzt[NZSUB[k]]++;
|
|
682
|
-
}
|
|
683
|
-
xlnzt[1] = 1;
|
|
684
|
-
for (i = 1; i <= n; i++) xlnzt[i+1] = xlnzt[i] + nzt[i];
|
|
685
|
-
|
|
686
|
-
// Transpose matrix twice to order column indexes
|
|
687
|
-
transpose(n, XLNZ, NZSUB, LNZ, xlnzt, nzsubt, lnzt, nzt);
|
|
688
|
-
transpose(n, xlnzt, nzsubt, lnzt, XLNZ, NZSUB, LNZ, nzt);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// Reclaim memory
|
|
692
|
-
free(xlnzt);
|
|
693
|
-
free(nzsubt);
|
|
694
|
-
free(lnzt);
|
|
695
|
-
free(nzt);
|
|
696
|
-
return errcode;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
void transpose(int n, int *il, int *jl, int *xl, int *ilt, int *jlt,
|
|
701
|
-
int *xlt, int *nzt)
|
|
702
|
-
/*
|
|
703
|
-
**---------------------------------------------------------------------
|
|
704
|
-
** Input: n = matrix order
|
|
705
|
-
** il,jl,xl = sparse storage scheme for original matrix
|
|
706
|
-
** nzt = work array
|
|
707
|
-
** Output: ilt,jlt,xlt = sparse storage scheme for transposed matrix
|
|
708
|
-
** Purpose: Determines sparse storage scheme for transpose of a matrix
|
|
709
|
-
**---------------------------------------------------------------------
|
|
710
|
-
*/
|
|
711
|
-
{
|
|
712
|
-
int i, j, k, kk;
|
|
713
|
-
|
|
714
|
-
for (i = 1; i <= n; i++) nzt[i] = 0;
|
|
715
|
-
for (i = 1; i <= n; i++)
|
|
716
|
-
{
|
|
717
|
-
for (k = il[i]; k < il[i+1]; k++)
|
|
718
|
-
{
|
|
719
|
-
j = jl[k];
|
|
720
|
-
kk = ilt[j] + nzt[j];
|
|
721
|
-
jlt[kk] = i;
|
|
722
|
-
xlt[kk] = xl[k];
|
|
723
|
-
nzt[j]++;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
int linsolve(Smatrix *sm, int n)
|
|
730
|
-
/*
|
|
731
|
-
**--------------------------------------------------------------
|
|
732
|
-
** Input: sm = sparse matrix struct
|
|
733
|
-
n = number of equations
|
|
734
|
-
** Output: sm->F = solution values
|
|
735
|
-
** returns 0 if solution found, or index of
|
|
736
|
-
** equation causing system to be ill-conditioned
|
|
737
|
-
** Purpose: solves sparse symmetric system of linear
|
|
738
|
-
** equations using Cholesky factorization
|
|
739
|
-
**
|
|
740
|
-
** NOTE: This procedure assumes that the solution matrix has
|
|
741
|
-
** been symbolically factorized with the positions of
|
|
742
|
-
** the lower triangular, off-diagonal, non-zero coeffs.
|
|
743
|
-
** stored in the following integer arrays:
|
|
744
|
-
** XLNZ (start position of each column in NZSUB)
|
|
745
|
-
** NZSUB (row index of each non-zero in each column)
|
|
746
|
-
** LNZ (position of each NZSUB entry in Aij array)
|
|
747
|
-
**
|
|
748
|
-
** This procedure has been adapted from subroutines GSFCT and
|
|
749
|
-
** GSSLV in the book "Computer Solution of Large Sparse
|
|
750
|
-
** Positive Definite Systems" by A. George and J. W-H Liu
|
|
751
|
-
** (Prentice-Hall, 1981).
|
|
752
|
-
**--------------------------------------------------------------
|
|
753
|
-
*/
|
|
754
|
-
{
|
|
755
|
-
double *Aii = sm->Aii;
|
|
756
|
-
double *Aij = sm->Aij;
|
|
757
|
-
double *B = sm->F;
|
|
758
|
-
double *temp = sm->temp;
|
|
759
|
-
int *LNZ = sm->LNZ;
|
|
760
|
-
int *XLNZ = sm->XLNZ;
|
|
761
|
-
int *NZSUB = sm->NZSUB;
|
|
762
|
-
int *link = sm->link;
|
|
763
|
-
int *first = sm->first;
|
|
764
|
-
|
|
765
|
-
int i, istop, istrt, isub, j, k, kfirst, newk;
|
|
766
|
-
double bj, diagj, ljk;
|
|
767
|
-
|
|
768
|
-
memset(temp, 0, (n + 1) * sizeof(double));
|
|
769
|
-
memset(link, 0, (n + 1) * sizeof(int));
|
|
770
|
-
memset(first, 0, (n + 1) * sizeof(int));
|
|
771
|
-
|
|
772
|
-
// Begin numerical factorization of matrix A into L
|
|
773
|
-
// Compute column L(*,j) for j = 1,...n
|
|
774
|
-
for (j = 1; j <= n; j++)
|
|
775
|
-
{
|
|
776
|
-
// For each column L(*,k) that affects L(*,j):
|
|
777
|
-
diagj = 0.0;
|
|
778
|
-
newk = link[j];
|
|
779
|
-
k = newk;
|
|
780
|
-
while (k != 0)
|
|
781
|
-
{
|
|
782
|
-
// Outer product modification of L(*,j) by
|
|
783
|
-
// L(*,k) starting at first[k] of L(*,k)
|
|
784
|
-
newk = link[k];
|
|
785
|
-
kfirst = first[k];
|
|
786
|
-
ljk = Aij[LNZ[kfirst]];
|
|
787
|
-
diagj += ljk*ljk;
|
|
788
|
-
istrt = kfirst + 1;
|
|
789
|
-
istop = XLNZ[k+1] - 1;
|
|
790
|
-
if (istop >= istrt)
|
|
791
|
-
{
|
|
792
|
-
|
|
793
|
-
// Before modification, update vectors 'first'
|
|
794
|
-
// and 'link' for future modification steps
|
|
795
|
-
first[k] = istrt;
|
|
796
|
-
isub = NZSUB[istrt];
|
|
797
|
-
link[k] = link[isub];
|
|
798
|
-
link[isub] = k;
|
|
799
|
-
|
|
800
|
-
// The actual mod is saved in vector 'temp'
|
|
801
|
-
for (i = istrt; i <= istop; i++)
|
|
802
|
-
{
|
|
803
|
-
isub = NZSUB[i];
|
|
804
|
-
temp[isub] += Aij[LNZ[i]]*ljk;
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
k = newk;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
// Apply the modifications accumulated
|
|
811
|
-
// in 'temp' to column L(*,j)
|
|
812
|
-
diagj = Aii[j] - diagj;
|
|
813
|
-
if (diagj <= 0.0) // Check for ill-conditioning
|
|
814
|
-
{
|
|
815
|
-
return j;
|
|
816
|
-
}
|
|
817
|
-
diagj = sqrt(diagj);
|
|
818
|
-
Aii[j] = diagj;
|
|
819
|
-
istrt = XLNZ[j];
|
|
820
|
-
istop = XLNZ[j+1] - 1;
|
|
821
|
-
if (istop >= istrt)
|
|
822
|
-
{
|
|
823
|
-
first[j] = istrt;
|
|
824
|
-
isub = NZSUB[istrt];
|
|
825
|
-
link[j] = link[isub];
|
|
826
|
-
link[isub] = j;
|
|
827
|
-
for (i = istrt; i <= istop; i++)
|
|
828
|
-
{
|
|
829
|
-
isub = NZSUB[i];
|
|
830
|
-
bj = (Aij[LNZ[i]] - temp[isub])/diagj;
|
|
831
|
-
Aij[LNZ[i]] = bj;
|
|
832
|
-
temp[isub] = 0.0;
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
} // next j
|
|
836
|
-
|
|
837
|
-
// Forward substitution
|
|
838
|
-
for (j = 1; j <= n; j++)
|
|
839
|
-
{
|
|
840
|
-
bj = B[j]/Aii[j];
|
|
841
|
-
B[j] = bj;
|
|
842
|
-
istrt = XLNZ[j];
|
|
843
|
-
istop = XLNZ[j+1] - 1;
|
|
844
|
-
if (istop >= istrt)
|
|
845
|
-
{
|
|
846
|
-
for (i = istrt; i <= istop; i++)
|
|
847
|
-
{
|
|
848
|
-
isub = NZSUB[i];
|
|
849
|
-
B[isub] -= Aij[LNZ[i]]*bj;
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
// Backward substitution
|
|
855
|
-
for (j = n; j >= 1; j--)
|
|
856
|
-
{
|
|
857
|
-
bj = B[j];
|
|
858
|
-
istrt = XLNZ[j];
|
|
859
|
-
istop = XLNZ[j+1] - 1;
|
|
860
|
-
if (istop >= istrt)
|
|
861
|
-
{
|
|
862
|
-
for (i = istrt; i <= istop; i++)
|
|
863
|
-
{
|
|
864
|
-
isub = NZSUB[i];
|
|
865
|
-
bj -= Aij[LNZ[i]]*B[isub];
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
B[j] = bj/Aii[j];
|
|
869
|
-
}
|
|
870
|
-
return 0;
|
|
871
|
-
}
|