1 #include <petsc-private/fortranimpl.h> 2 #include <petscmat.h> 3 4 #if defined(PETSC_HAVE_FORTRAN_CAPS) 5 #define matdestroymatrices_ MATDESTROYMATRICES 6 #define matgetfactor_ MATGETFACTOR 7 #define matfactorgetsolverpackage_ MATFACTORGETSOLVERPACKAGE 8 #define matgetrowij_ MATGETROWIJ 9 #define matrestorerowij_ MATRESTOREROWIJ 10 #define matgetrow_ MATGETROW 11 #define matrestorerow_ MATRESTOREROW 12 #define matload_ MATLOAD 13 #define matview_ MATVIEW 14 #define matseqaijgetarray_ MATSEQAIJGETARRAY 15 #define matseqaijrestorearray MATSEQAIJRESTOREARRAY 16 #define matdensegetarray_ MATDENSEGETARRAY 17 #define matdenserestorearray_ MATDENSERESTOREARRAY 18 #define matconvert_ MATCONVERT 19 #define matgetsubmatrices_ MATGETSUBMATRICES 20 #define matzerorowscolumns_ MATZEROROWSCOLUMNS 21 #define matzerorowscolumnsis_ MATZEROROWSCOLUMNSIS 22 #define matzerorowsstencil_ MATZEROROWSSTENCIL 23 #define matzerorowscolumnsstencil_ MATZEROROWSCOLUMNSSTENCIL 24 #define matzerorows_ MATZEROROWS 25 #define matzerorowsis_ MATZEROROWSIS 26 #define matzerorowslocal_ MATZEROROWSLOCAL 27 #define matzerorowslocalis_ MATZEROROWSLOCALIS 28 #define matzerorowscolumnslocal_ MATZEROROWSCOLUMNSLOCAL 29 #define matzerorowscolumnslocalis_ MATZEROROWSCOLUMNSLOCALIS 30 #define matsetoptionsprefix_ MATSETOPTIONSPREFIX 31 #define matgetvecs_ MATGETVECS 32 #define matnullspaceremove_ MATNULLSPACEREMOVE 33 #define matgetinfo_ MATGETINFO 34 #define matlufactor_ MATLUFACTOR 35 #define matilufactor_ MATILUFACTOR 36 #define matlufactorsymbolic_ MATLUFACTORSYMBOLIC 37 #define matlufactornumeric_ MATLUFACTORNUMERIC 38 #define matcholeskyfactor_ MATCHOLESKYFACTOR 39 #define matcholeskyfactorsymbolic_ MATCHOLESKYFACTORSYMBOLIC 40 #define matcholeskyfactornumeric_ MATCHOLESKYFACTORNUMERIC 41 #define matilufactorsymbolic_ MATILUFACTORSYMBOLIC 42 #define maticcfactorsymbolic_ MATICCFACTORSYMBOLIC 43 #define maticcfactor_ MATICCFACTOR 44 #define matfactorinfoinitialize_ MATFACTORINFOINITIALIZE 45 #define matnullspacesetfunction_ MATNULLSPACESETFUNCTION 46 #define matfindnonzerorows_ MATFINDNONZEROROWS 47 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 48 #define matdestroymatrices_ matdestroymatrices_ 49 #define matgetfactor_ matgetfactor 50 #define matfactorgetsolverpackage_ matfactorgetsolverpackage 51 #define matgetvecs_ matgetvecs 52 #define matgetrowij_ matgetrowij 53 #define matrestorerowij_ matrestorerowij 54 #define matgetrow_ matgetrow 55 #define matrestorerow_ matrestorerow 56 #define matview_ matview 57 #define matload_ matload 58 #define matseqaijgetarray_ matseqaijgetarray 59 #define matseqaijrestorearray_ matseqaijrestorearray 60 #define matdensegetarray_ matdensegetarray 61 #define matdenserestorearray_ matdenserestorearray 62 #define matconvert_ matconvert 63 #define matgetsubmatrices_ matgetsubmatrices 64 #define matzerorowscolumns_ matzerorowscolumns 65 #define matzerorowscolumnsis_ matzerorowscolumnsis 66 #define matzerorowsstencil_ matzerorowsstencil 67 #define matzerorowscolumnsstencil_ matzerorowscolumnsstencil 68 #define matzerorows_ matzerorows 69 #define matzerorowsis_ matzerorowsis 70 #define matzerorowslocal_ matzerorowslocal 71 #define matzerorowslocalis_ matzerorowslocalis 72 #define matzerorowscolumnslocal_ matzerorowscolumnslocal 73 #define matzerorowscolumnslocalis_ matzerorowscolumnslocalis 74 #define matsetoptionsprefix_ matsetoptionsprefix 75 #define matnullspaceremove_ matnullspaceremove 76 #define matgetinfo_ matgetinfo 77 #define matlufactor_ matlufactor 78 #define matilufactor_ matilufactor 79 #define matlufactorsymbolic_ matlufactorsymbolic 80 #define matlufactornumeric_ matlufactornumeric 81 #define matcholeskyfactor_ matcholeskyfactor 82 #define matcholeskyfactorsymbolic_ matcholeskyfactorsymbolic 83 #define matcholeskyfactornumeric_ matcholeskyfactornumeric 84 #define matilufactorsymbolic_ matilufactorsymbolic 85 #define maticcfactorsymbolic_ maticcfactorsymbolic 86 #define maticcfactor_ maticcfactor 87 #define matfactorinfoinitialize_ matfactorinfoinitialize 88 #define matnullspacesetfunction_ matnullspacesetfunction 89 #define matfindnonzerorows_ matfindnonzerorows 90 #endif 91 92 EXTERN_C_BEGIN 93 94 static PetscErrorCode ournullfunction(MatNullSpace sp,Vec x,void *ctx) 95 { 96 PetscErrorCode ierr = 0; 97 (*(void (PETSC_STDCALL *)(MatNullSpace*,Vec*,void*,PetscErrorCode*))(((PetscObject)sp)->fortran_func_pointers[0]))(&sp,&x,ctx,&ierr);CHKERRQ(ierr); 98 return 0; 99 } 100 101 void PETSC_STDCALL matnullspacesetfunction_(MatNullSpace *sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx,PetscErrorCode *ierr) 102 { 103 PetscObjectAllocateFortranPointers(*sp,1); 104 ((PetscObject)*sp)->fortran_func_pointers[0] = (PetscVoidFunction)rem; 105 *ierr = MatNullSpaceSetFunction(*sp,ournullfunction,ctx); 106 } 107 108 void PETSC_STDCALL matgetvecs_(Mat *mat,Vec *right,Vec *left, int *ierr) 109 { 110 CHKFORTRANNULLOBJECT(right); 111 CHKFORTRANNULLOBJECT(left); 112 *ierr = MatGetVecs(*mat,right,left); 113 } 114 115 void PETSC_STDCALL matgetrowij_(Mat *B,PetscInt *shift,PetscBool *sym,PetscBool *blockcompressed,PetscInt *n,PetscInt *ia,size_t *iia, 116 PetscInt *ja,size_t *jja,PetscBool *done,PetscErrorCode *ierr) 117 { 118 const PetscInt *IA,*JA; 119 *ierr = MatGetRowIJ(*B,*shift,*sym,*blockcompressed,n,&IA,&JA,done);if (*ierr) return; 120 *iia = PetscIntAddressToFortran(ia,(PetscInt*)IA); 121 *jja = PetscIntAddressToFortran(ja,(PetscInt*)JA); 122 } 123 124 void PETSC_STDCALL matrestorerowij_(Mat *B,PetscInt *shift,PetscBool *sym,PetscBool *blockcompressed, PetscInt *n,PetscInt *ia,size_t *iia, 125 PetscInt *ja,size_t *jja,PetscBool *done,PetscErrorCode *ierr) 126 { 127 const PetscInt *IA = PetscIntAddressFromFortran(ia,*iia),*JA = PetscIntAddressFromFortran(ja,*jja); 128 *ierr = MatRestoreRowIJ(*B,*shift,*sym,*blockcompressed,n,&IA,&JA,done); 129 } 130 131 /* 132 This is a poor way of storing the column and value pointers 133 generated by MatGetRow() to be returned with MatRestoreRow() 134 but there is not natural,good place else to store them. Hence 135 Fortran programmers can only have one outstanding MatGetRows() 136 at a time. 137 */ 138 static PetscErrorCode matgetrowactive = 0; 139 static const PetscInt *my_ocols = 0; 140 static const PetscScalar *my_ovals = 0; 141 142 void PETSC_STDCALL matgetrow_(Mat *mat,PetscInt *row,PetscInt *ncols,PetscInt *cols,PetscScalar *vals,PetscErrorCode *ierr) 143 { 144 const PetscInt **oocols = &my_ocols; 145 const PetscScalar **oovals = &my_ovals; 146 147 if (matgetrowactive) { 148 PetscError(PETSC_COMM_SELF,__LINE__,"MatGetRow_Fortran",__FILE__,__SDIR__,PETSC_ERR_ARG_WRONGSTATE,PETSC_ERROR_INITIAL, 149 "Cannot have two MatGetRow() active simultaneously\n\ 150 call MatRestoreRow() before calling MatGetRow() a second time"); 151 *ierr = 1; 152 return; 153 } 154 155 CHKFORTRANNULLINTEGER(cols); if (!cols) oocols = PETSC_NULL; 156 CHKFORTRANNULLSCALAR(vals); if (!vals) oovals = PETSC_NULL; 157 158 *ierr = MatGetRow(*mat,*row,ncols,oocols,oovals); 159 if (*ierr) return; 160 161 if (oocols) { *ierr = PetscMemcpy(cols,my_ocols,(*ncols)*sizeof(PetscInt)); if (*ierr) return;} 162 if (oovals) { *ierr = PetscMemcpy(vals,my_ovals,(*ncols)*sizeof(PetscScalar)); if (*ierr) return; } 163 matgetrowactive = 1; 164 } 165 166 void PETSC_STDCALL matrestorerow_(Mat *mat,PetscInt *row,PetscInt *ncols,PetscInt *cols,PetscScalar *vals,PetscErrorCode *ierr) 167 { 168 const PetscInt **oocols = &my_ocols; 169 const PetscScalar **oovals = &my_ovals; 170 if (!matgetrowactive) { 171 PetscError(PETSC_COMM_SELF,__LINE__,"MatRestoreRow_Fortran",__FILE__,__SDIR__,PETSC_ERR_ARG_WRONGSTATE,PETSC_ERROR_INITIAL, 172 "Must call MatGetRow() first"); 173 *ierr = 1; 174 return; 175 } 176 CHKFORTRANNULLINTEGER(cols); if (!cols) oocols = PETSC_NULL; 177 CHKFORTRANNULLSCALAR(vals); if (!vals) oovals = PETSC_NULL; 178 179 *ierr = MatRestoreRow(*mat,*row,ncols,oocols,oovals); 180 matgetrowactive = 0; 181 } 182 183 void PETSC_STDCALL matview_(Mat *mat,PetscViewer *vin,PetscErrorCode *ierr) 184 { 185 PetscViewer v; 186 PetscPatchDefaultViewers_Fortran(vin,v); 187 *ierr = MatView(*mat,v); 188 } 189 190 void PETSC_STDCALL matload_(Mat *mat,PetscViewer *vin,PetscErrorCode *ierr) 191 { 192 PetscViewer v; 193 PetscPatchDefaultViewers_Fortran(vin,v); 194 *ierr = MatLoad(*mat,v); 195 } 196 197 void PETSC_STDCALL matseqaijgetarray_(Mat *mat,PetscScalar *fa,size_t *ia,PetscErrorCode *ierr) 198 { 199 PetscScalar *mm; 200 PetscInt m,n; 201 202 *ierr = MatSeqAIJGetArray(*mat,&mm); if (*ierr) return; 203 *ierr = MatGetSize(*mat,&m,&n); if (*ierr) return; 204 *ierr = PetscScalarAddressToFortran((PetscObject)*mat,1,fa,mm,m*n,ia); if (*ierr) return; 205 } 206 207 void PETSC_STDCALL matseqaijrestorearray_(Mat *mat,PetscScalar *fa,size_t *ia,PetscErrorCode *ierr) 208 { 209 PetscScalar *lx; 210 PetscInt m,n; 211 212 *ierr = MatGetSize(*mat,&m,&n); if (*ierr) return; 213 *ierr = PetscScalarAddressFromFortran((PetscObject)*mat,fa,*ia,m*n,&lx);if (*ierr) return; 214 *ierr = MatSeqAIJRestoreArray(*mat,&lx);if (*ierr) return; 215 } 216 217 void PETSC_STDCALL matdensegetarray_(Mat *mat,PetscScalar *fa,size_t *ia,PetscErrorCode *ierr) 218 { 219 PetscScalar *mm; 220 PetscInt m,n; 221 222 *ierr = MatDenseGetArray(*mat,&mm); if (*ierr) return; 223 *ierr = MatGetSize(*mat,&m,&n); if (*ierr) return; 224 *ierr = PetscScalarAddressToFortran((PetscObject)*mat,1,fa,mm,m*n,ia); if (*ierr) return; 225 } 226 227 void PETSC_STDCALL matdenserestorearray_(Mat *mat,PetscScalar *fa,size_t *ia,PetscErrorCode *ierr) 228 { 229 PetscScalar *lx; 230 PetscInt m,n; 231 232 *ierr = MatGetSize(*mat,&m,&n); if (*ierr) return; 233 *ierr = PetscScalarAddressFromFortran((PetscObject)*mat,fa,*ia,m*n,&lx);if (*ierr) return; 234 *ierr = MatDenseRestoreArray(*mat,&lx);if (*ierr) return; 235 } 236 237 void PETSC_STDCALL matfactorgetsolverpackage_(Mat *mat,CHAR name PETSC_MIXED_LEN(len),PetscErrorCode *ierr PETSC_END_LEN(len)) 238 { 239 const char *tname; 240 241 *ierr = MatFactorGetSolverPackage(*mat,&tname);if (*ierr) return; 242 if (name != PETSC_NULL_CHARACTER_Fortran) { 243 *ierr = PetscStrncpy(name,tname,len);if (*ierr) return; 244 } 245 FIXRETURNCHAR(PETSC_TRUE,name,len); 246 } 247 248 void PETSC_STDCALL matgetfactor_(Mat *mat,CHAR outtype PETSC_MIXED_LEN(len),MatFactorType *ftype,Mat *M,PetscErrorCode *ierr PETSC_END_LEN(len)) 249 { 250 char *t; 251 FIXCHAR(outtype,len,t); 252 *ierr = MatGetFactor(*mat,t,*ftype,M); 253 FREECHAR(outtype,t); 254 } 255 256 void PETSC_STDCALL matconvert_(Mat *mat,CHAR outtype PETSC_MIXED_LEN(len),MatReuse *reuse,Mat *M,PetscErrorCode *ierr PETSC_END_LEN(len)) 257 { 258 char *t; 259 FIXCHAR(outtype,len,t); 260 *ierr = MatConvert(*mat,t,*reuse,M); 261 FREECHAR(outtype,t); 262 } 263 264 /* 265 MatGetSubmatrices() is slightly different from C since the 266 Fortran provides the array to hold the submatrix objects,while in C that 267 array is allocated by the MatGetSubmatrices() 268 */ 269 void PETSC_STDCALL matgetsubmatrices_(Mat *mat,PetscInt *n,IS *isrow,IS *iscol,MatReuse *scall,Mat *smat,PetscErrorCode *ierr) 270 { 271 Mat *lsmat; 272 PetscInt i; 273 274 if (*scall == MAT_INITIAL_MATRIX) { 275 *ierr = MatGetSubMatrices(*mat,*n,isrow,iscol,*scall,&lsmat); 276 for (i=0; i<*n; i++) { 277 smat[i] = lsmat[i]; 278 } 279 *ierr = PetscFree(lsmat); 280 } else { 281 *ierr = MatGetSubMatrices(*mat,*n,isrow,iscol,*scall,&smat); 282 } 283 } 284 285 /* 286 MatDestroyMatrices() is slightly different from C since the 287 Fortran provides the array to hold the submatrix objects,while in C that 288 array is allocated by the MatGetSubmatrices() 289 */ 290 void PETSC_STDCALL matdestroymatrices_(Mat *mat,PetscInt *n,Mat *smat,PetscErrorCode *ierr) 291 { 292 PetscInt i; 293 294 for (i=0; i<*n; i++) { 295 *ierr = MatDestroy(&smat[i]);if (*ierr) return; 296 } 297 } 298 299 void PETSC_STDCALL matzerorowscolumns_(Mat *mat,PetscInt *numRows,PetscInt *rows,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 300 { 301 CHKFORTRANNULLOBJECTDEREFERENCE(x); 302 CHKFORTRANNULLOBJECTDEREFERENCE(b); 303 *ierr = MatZeroRowsColumns(*mat,*numRows,rows,*diag,*x,*b); 304 } 305 306 void PETSC_STDCALL matzerorowscolumnsis_(Mat *mat,IS *is,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 307 { 308 CHKFORTRANNULLOBJECTDEREFERENCE(x); 309 CHKFORTRANNULLOBJECTDEREFERENCE(b); 310 *ierr = MatZeroRowsColumnsIS(*mat,*is,*diag,*x,*b); 311 } 312 313 void PETSC_STDCALL matzerorowsstencil_(Mat *mat,PetscInt *numRows,MatStencil *rows,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 314 { 315 CHKFORTRANNULLOBJECTDEREFERENCE(x); 316 CHKFORTRANNULLOBJECTDEREFERENCE(b); 317 *ierr = MatZeroRowsStencil(*mat,*numRows,rows,*diag,*x,*b); 318 } 319 320 void PETSC_STDCALL matzerorowscolumnsstencil_(Mat *mat,PetscInt *numRows,MatStencil *rows,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 321 { 322 CHKFORTRANNULLOBJECTDEREFERENCE(x); 323 CHKFORTRANNULLOBJECTDEREFERENCE(b); 324 *ierr = MatZeroRowsColumnsStencil(*mat,*numRows,rows,*diag,*x,*b); 325 } 326 327 void PETSC_STDCALL matzerorows_(Mat *mat,PetscInt *numRows,PetscInt *rows,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 328 { 329 CHKFORTRANNULLOBJECTDEREFERENCE(x); 330 CHKFORTRANNULLOBJECTDEREFERENCE(b); 331 *ierr = MatZeroRows(*mat,*numRows,rows,*diag,*x,*b); 332 } 333 334 void PETSC_STDCALL matzerorowsis_(Mat *mat,IS *is,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 335 { 336 CHKFORTRANNULLOBJECTDEREFERENCE(x); 337 CHKFORTRANNULLOBJECTDEREFERENCE(b); 338 *ierr = MatZeroRowsIS(*mat,*is,*diag,*x,*b); 339 } 340 341 void PETSC_STDCALL matzerorowslocal_(Mat *mat,PetscInt *numRows,PetscInt *rows,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 342 { 343 CHKFORTRANNULLOBJECTDEREFERENCE(x); 344 CHKFORTRANNULLOBJECTDEREFERENCE(b); 345 *ierr = MatZeroRowsLocal(*mat,*numRows,rows,*diag,*x,*b); 346 } 347 348 void PETSC_STDCALL matzerorowslocalis_(Mat *mat,IS *is,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 349 { 350 CHKFORTRANNULLOBJECTDEREFERENCE(x); 351 CHKFORTRANNULLOBJECTDEREFERENCE(b); 352 *ierr = MatZeroRowsLocalIS(*mat,*is,*diag,*x,*b); 353 } 354 355 void PETSC_STDCALL matzerorowscolumnslocal_(Mat *mat,PetscInt *numRows,PetscInt *rows,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 356 { 357 CHKFORTRANNULLOBJECTDEREFERENCE(x); 358 CHKFORTRANNULLOBJECTDEREFERENCE(b); 359 *ierr = MatZeroRowsColumnsLocal(*mat,*numRows,rows,*diag,*x,*b); 360 } 361 362 void PETSC_STDCALL matzerorowscolumnslocalis_(Mat *mat,IS *is,PetscScalar *diag,Vec *x,Vec *b,PetscErrorCode *ierr) 363 { 364 CHKFORTRANNULLOBJECTDEREFERENCE(x); 365 CHKFORTRANNULLOBJECTDEREFERENCE(b); 366 *ierr = MatZeroRowsColumnsLocalIS(*mat,*is,*diag,*x,*b); 367 } 368 369 void PETSC_STDCALL matsetoptionsprefix_(Mat *mat,CHAR prefix PETSC_MIXED_LEN(len),PetscErrorCode *ierr PETSC_END_LEN(len)) 370 { 371 char *t; 372 373 FIXCHAR(prefix,len,t); 374 *ierr = MatSetOptionsPrefix(*mat,t); 375 FREECHAR(prefix,t); 376 } 377 378 void PETSC_STDCALL matnullspaceremove_(MatNullSpace *sp,Vec *vec,Vec *out,PetscErrorCode *ierr) 379 { 380 CHKFORTRANNULLOBJECT(out); 381 *ierr = MatNullSpaceRemove(*sp,*vec,out); 382 } 383 384 void PETSC_STDCALL matgetinfo_(Mat *mat,MatInfoType *flag,MatInfo *info, int *__ierr) 385 { 386 *__ierr = MatGetInfo(*mat,*flag,info); 387 } 388 389 void PETSC_STDCALL matlufactor_(Mat *mat,IS *row,IS *col, MatFactorInfo *info, int *__ierr) 390 { 391 *__ierr = MatLUFactor(*mat,*row,*col,info); 392 } 393 394 void PETSC_STDCALL matilufactor_(Mat *mat,IS *row,IS *col, MatFactorInfo *info, int *__ierr) 395 { 396 *__ierr = MatILUFactor(*mat,*row,*col,info); 397 } 398 399 void PETSC_STDCALL matlufactorsymbolic_(Mat *fact,Mat *mat,IS *row,IS *col, MatFactorInfo *info, int *__ierr) 400 { 401 *__ierr = MatLUFactorSymbolic(*fact,*mat,*row,*col,info); 402 } 403 404 void PETSC_STDCALL matlufactornumeric_(Mat *fact,Mat *mat, MatFactorInfo *info, int *__ierr) 405 { 406 *__ierr = MatLUFactorNumeric(*fact,*mat,info); 407 } 408 409 void PETSC_STDCALL matcholeskyfactor_(Mat *mat,IS *perm, MatFactorInfo *info, int *__ierr) 410 { 411 *__ierr = MatCholeskyFactor(*mat,*perm,info); 412 } 413 414 void PETSC_STDCALL matcholeskyfactorsymbolic_(Mat *fact,Mat *mat,IS *perm, MatFactorInfo *info, int *__ierr) 415 { 416 *__ierr = MatCholeskyFactorSymbolic(*fact,*mat,*perm,info); 417 } 418 419 void PETSC_STDCALL matcholeskyfactornumeric_(Mat *fact,Mat *mat, MatFactorInfo *info, int *__ierr) 420 { 421 *__ierr = MatCholeskyFactorNumeric(*fact,*mat,info); 422 } 423 424 void PETSC_STDCALL matilufactorsymbolic_(Mat *fact,Mat *mat,IS *row,IS *col, MatFactorInfo *info, int *__ierr) 425 { 426 *__ierr = MatILUFactorSymbolic(*fact,*mat,*row,*col,info); 427 } 428 429 void PETSC_STDCALL maticcfactorsymbolic_(Mat *fact,Mat *mat,IS *perm, MatFactorInfo *info, int *__ierr) 430 { 431 *__ierr = MatICCFactorSymbolic(*fact,*mat,*perm,info); 432 } 433 434 void PETSC_STDCALL maticcfactor_(Mat *mat,IS *row, MatFactorInfo* info, int *__ierr) 435 { 436 *__ierr = MatICCFactor(*mat,*row,info); 437 } 438 439 void PETSC_STDCALL matfactorinfoinitialize_(MatFactorInfo *info, int *__ierr) 440 { 441 *__ierr = MatFactorInfoInitialize(info); 442 } 443 444 EXTERN_C_END 445