1 // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC. 2 // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707. 3 // All Rights reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed-impl.h> 18 #include <string.h> 19 #include "ceed-ref.h" 20 21 static int CeedOperatorDestroy_Ref(CeedOperator op) { 22 CeedOperator_Ref *impl = op->data; 23 int ierr; 24 25 for (CeedInt i=0; i<impl->numein+impl->numeout; i++) { 26 ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr); 27 } 28 ierr = CeedFree(&impl->evecs); CeedChk(ierr); 29 ierr = CeedFree(&impl->edata); CeedChk(ierr); 30 31 for (CeedInt i=0; i<impl->numqin+impl->numqout; i++) { 32 ierr = CeedFree(&impl->qdata_alloc[i]); CeedChk(ierr); 33 } 34 ierr = CeedFree(&impl->qdata_alloc); CeedChk(ierr); 35 ierr = CeedFree(&impl->qdata); CeedChk(ierr); 36 37 ierr = CeedFree(&impl->indata); CeedChk(ierr); 38 ierr = CeedFree(&impl->outdata); CeedChk(ierr); 39 40 ierr = CeedFree(&op->data); CeedChk(ierr); 41 return 0; 42 } 43 44 /* 45 Setup infields or outfields 46 */ 47 static int CeedOperatorSetupFields_Ref(struct CeedQFunctionField qfields[16], 48 struct CeedOperatorField ofields[16], 49 CeedVector *evecs, CeedScalar **qdata, 50 CeedScalar **qdata_alloc, CeedScalar **indata, 51 CeedInt starti, CeedInt starte, 52 CeedInt startq, CeedInt numfields, CeedInt Q) { 53 CeedInt dim, ierr, ie=starte, iq=startq, ncomp; 54 55 // Loop over fields 56 for (CeedInt i=0; i<numfields; i++) { 57 if (ofields[i].Erestrict != CEED_RESTRICTION_IDENTITY) { 58 ierr = CeedElemRestrictionCreateVector(ofields[i].Erestrict, NULL, &evecs[ie]); 59 CeedChk(ierr); 60 ie++; 61 } 62 CeedEvalMode emode = qfields[i].emode; 63 switch(emode) { 64 case CEED_EVAL_NONE: 65 break; // No action 66 case CEED_EVAL_INTERP: 67 ncomp = qfields[i].ncomp; 68 ierr = CeedMalloc(Q*ncomp, &qdata_alloc[iq]); CeedChk(ierr); 69 qdata[i + starti] = qdata_alloc[iq]; 70 iq++; 71 break; 72 case CEED_EVAL_GRAD: 73 ncomp = qfields[i].ncomp; 74 dim = ofields[i].basis->dim; 75 ierr = CeedMalloc(Q*ncomp*dim, &qdata_alloc[iq]); CeedChk(ierr); 76 qdata[i + starti] = qdata_alloc[iq]; 77 iq++; 78 break; 79 case CEED_EVAL_WEIGHT: // Only on input fields 80 ierr = CeedMalloc(Q, &qdata_alloc[iq]); CeedChk(ierr); 81 ierr = CeedBasisApply(ofields[iq].basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 82 NULL, qdata_alloc[iq]); CeedChk(ierr); 83 qdata[i] = qdata_alloc[iq]; 84 indata[i] = qdata[i]; 85 iq++; 86 break; 87 case CEED_EVAL_DIV: 88 break; // Not implimented 89 case CEED_EVAL_CURL: 90 break; // Not implimented 91 } 92 } 93 return 0; 94 } 95 96 /* 97 CeedOperator needs to connect all the named fields (be they active or passive) 98 to the named inputs and outputs of its CeedQFunction. 99 */ 100 static int CeedOperatorSetup_Ref(CeedOperator op) { 101 if (op->setupdone) return 0; 102 CeedOperator_Ref *opref = op->data; 103 CeedQFunction qf = op->qf; 104 CeedInt Q = op->numqpoints; 105 int ierr; 106 107 // Count infield and outfield array sizes and evectors 108 for (CeedInt i=0; i<qf->numinputfields; i++) { 109 CeedEvalMode emode = qf->inputfields[i].emode; 110 opref->numqin += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD) + !! 111 (emode & CEED_EVAL_WEIGHT); 112 opref->numein += 113 (op->inputfields[i].Erestrict != 114 CEED_RESTRICTION_IDENTITY); // Need E-vector when non-identity restriction exists 115 } 116 for (CeedInt i=0; i<qf->numoutputfields; i++) { 117 CeedEvalMode emode = qf->outputfields[i].emode; 118 opref->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD); 119 opref->numeout += (op->outputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY); 120 } 121 122 // Allocate 123 ierr = CeedCalloc(opref->numein + opref->numeout, &opref->evecs); CeedChk(ierr); 124 ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->edata); 125 CeedChk(ierr); 126 127 ierr = CeedCalloc(opref->numqin + opref->numqout, &opref->qdata_alloc); 128 CeedChk(ierr); 129 ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->qdata); 130 CeedChk(ierr); 131 132 ierr = CeedCalloc(16, &opref->indata); CeedChk(ierr); 133 ierr = CeedCalloc(16, &opref->outdata); CeedChk(ierr); 134 135 // Set up infield and outfield pointer arrays 136 // Infields 137 ierr = CeedOperatorSetupFields_Ref(qf->inputfields, op->inputfields, 138 opref->evecs, opref->qdata, opref->qdata_alloc, 139 opref->indata, 0, 0, 0, 140 qf->numinputfields, Q); CeedChk(ierr); 141 142 // Outfields 143 ierr = CeedOperatorSetupFields_Ref(qf->outputfields, op->outputfields, 144 opref->evecs, opref->qdata, opref->qdata_alloc, 145 opref->indata, qf->numinputfields, opref->numein, 146 opref->numqin, qf->numoutputfields, Q); CeedChk(ierr); 147 148 // Output Qvecs 149 for (CeedInt i=0; i<qf->numoutputfields; i++) { 150 CeedEvalMode emode = qf->outputfields[i].emode; 151 if (emode != CEED_EVAL_NONE) { 152 opref->outdata[i] = opref->qdata[i + qf->numinputfields]; 153 } 154 } 155 156 op->setupdone = 1; 157 158 return 0; 159 } 160 161 static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec, 162 CeedVector outvec, CeedRequest *request) { 163 CeedOperator_Ref *opref = op->data; 164 CeedInt Q = op->numqpoints, elemsize; 165 int ierr; 166 CeedQFunction qf = op->qf; 167 CeedTransposeMode lmode = CEED_NOTRANSPOSE; 168 CeedScalar *vec_temp; 169 170 // Setup 171 ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr); 172 173 // Input Evecs and Restriction 174 for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) { 175 // No Restriction 176 if (op->inputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 177 CeedEvalMode emode = qf->inputfields[i].emode; 178 if (emode & CEED_EVAL_WEIGHT) { 179 } else { 180 // Active 181 if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) { 182 ierr = CeedVectorGetArrayRead(invec, CEED_MEM_HOST, 183 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 184 // Passive 185 } else { 186 ierr = CeedVectorGetArrayRead(op->inputfields[i].vec, CEED_MEM_HOST, 187 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 188 } 189 } 190 } else { 191 // Restriction 192 // Zero evec 193 ierr = CeedVectorGetArray(opref->evecs[iein], CEED_MEM_HOST, &vec_temp); 194 CeedChk(ierr); 195 for (CeedInt j=0; j<opref->evecs[iein]->length; j++) 196 vec_temp[j] = 0.; 197 ierr = CeedVectorRestoreArray(opref->evecs[iein], &vec_temp); CeedChk(ierr); 198 // Active 199 if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) { 200 // Restrict 201 ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE, 202 lmode, invec, opref->evecs[iein], 203 request); CeedChk(ierr); 204 // Get evec 205 ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST, 206 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 207 iein++; 208 } else { 209 // Passive 210 // Restrict 211 ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE, 212 lmode, op->inputfields[i].vec, opref->evecs[iein], 213 request); CeedChk(ierr); 214 // Get evec 215 ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST, 216 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 217 iein++; 218 } 219 } 220 } 221 222 // Output Evecs 223 for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) { 224 // No Restriction 225 if (op->outputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 226 // Active 227 if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) { 228 ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST, 229 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 230 } else { 231 // Passive 232 ierr = CeedVectorGetArray(op->outputfields[i].vec, CEED_MEM_HOST, 233 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 234 } 235 } else { 236 // Restriction 237 ierr = CeedVectorGetArray(opref->evecs[ieout], CEED_MEM_HOST, 238 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 239 ieout++; 240 } 241 } 242 243 // Loop through elements 244 for (CeedInt e=0; e<op->numelements; e++) { 245 // Input basis apply if needed 246 for (CeedInt i=0; i<qf->numinputfields; i++) { 247 // Get elemsize 248 if (op->inputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY) { 249 elemsize = op->inputfields[i].Erestrict->elemsize; 250 } else { 251 elemsize = Q; 252 } 253 // Get emode, ncomp 254 CeedEvalMode emode = qf->inputfields[i].emode; 255 CeedInt ncomp = qf->inputfields[i].ncomp; 256 // Basis action 257 switch(emode) { 258 case CEED_EVAL_NONE: 259 opref->indata[i] = &opref->edata[i][e*Q*ncomp]; 260 break; 261 case CEED_EVAL_INTERP: 262 ierr = CeedBasisApply(op->inputfields[i].basis, 1, CEED_NOTRANSPOSE, 263 CEED_EVAL_INTERP, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]); 264 CeedChk(ierr); 265 opref->indata[i] = opref->qdata[i]; 266 break; 267 case CEED_EVAL_GRAD: 268 ierr = CeedBasisApply(op->inputfields[i].basis, 1, CEED_NOTRANSPOSE, 269 CEED_EVAL_GRAD, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]); 270 CeedChk(ierr); 271 opref->indata[i] = opref->qdata[i]; 272 break; 273 case CEED_EVAL_WEIGHT: 274 break; // No action 275 case CEED_EVAL_DIV: 276 break; // Not implimented 277 case CEED_EVAL_CURL: 278 break; // Not implimented 279 } 280 } 281 // Output pointers 282 for (CeedInt i=0; i<qf->numoutputfields; i++) { 283 CeedEvalMode emode = qf->outputfields[i].emode; 284 if (emode == CEED_EVAL_NONE) { 285 CeedInt ncomp = qf->outputfields[i].ncomp; 286 opref->outdata[i] = &opref->edata[i + qf->numinputfields][e*Q*ncomp]; 287 } 288 } 289 // Q function 290 ierr = CeedQFunctionApply(op->qf, Q, (const CeedScalar * const*) opref->indata, 291 opref->outdata); CeedChk(ierr); 292 293 // Output basis apply if needed 294 for (CeedInt i=0; i<qf->numoutputfields; i++) { 295 // Get elemsize 296 if (op->outputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY) { 297 elemsize = op->outputfields[i].Erestrict->elemsize; 298 } else { 299 elemsize = Q; 300 } 301 // Get emode, ncomp 302 CeedInt ncomp = qf->outputfields[i].ncomp; 303 CeedEvalMode emode = qf->outputfields[i].emode; 304 // Basis action 305 switch(emode) { 306 case CEED_EVAL_NONE: 307 break; // No action 308 case CEED_EVAL_INTERP: 309 ierr = CeedBasisApply(op->outputfields[i].basis, 1, CEED_TRANSPOSE, 310 CEED_EVAL_INTERP, opref->outdata[i], 311 &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); CeedChk(ierr); 312 break; 313 case CEED_EVAL_GRAD: 314 ierr = CeedBasisApply(op->outputfields[i].basis, 1, CEED_TRANSPOSE, 315 CEED_EVAL_GRAD, 316 opref->outdata[i], &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); 317 CeedChk(ierr); 318 break; 319 case CEED_EVAL_WEIGHT: 320 break; // Should not occur 321 case CEED_EVAL_DIV: 322 break; // Not implimented 323 case CEED_EVAL_CURL: 324 break; // Not implimented 325 } 326 } 327 } 328 329 // Output restriction 330 for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) { 331 // No Restriction 332 if (op->outputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 333 // Active 334 if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) { 335 ierr = CeedVectorRestoreArray(outvec, &opref->edata[i + qf->numinputfields]); 336 CeedChk(ierr); 337 } else { 338 // Passive 339 ierr = CeedVectorRestoreArray(op->outputfields[i].vec, 340 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 341 } 342 } else { 343 // Restriction 344 // Active 345 if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) { 346 // Restore evec 347 ierr = CeedVectorRestoreArray(opref->evecs[ieout], 348 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 349 // Zero lvec 350 ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST, &vec_temp); CeedChk(ierr); 351 for (CeedInt j=0; j<outvec->length; j++) 352 vec_temp[j] = 0.; 353 ierr = CeedVectorRestoreArray(outvec, &vec_temp); CeedChk(ierr); 354 // Restrict 355 ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE, 356 lmode, opref->evecs[ieout], outvec, request); CeedChk(ierr); 357 ieout++; 358 } else { 359 // Passive 360 // Restore evec 361 ierr = CeedVectorRestoreArray(opref->evecs[ieout], 362 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 363 // Zero lvec 364 ierr = CeedVectorGetArray(op->outputfields[i].vec, CEED_MEM_HOST, &vec_temp); 365 CeedChk(ierr); 366 for (CeedInt j=0; j<op->outputfields[i].vec->length; j++) 367 vec_temp[j] = 0.; 368 ierr = CeedVectorRestoreArray(op->outputfields[i].vec, &vec_temp); 369 CeedChk(ierr); 370 // Restrict 371 ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE, 372 lmode, opref->evecs[ieout], op->outputfields[i].vec, 373 request); CeedChk(ierr); 374 ieout++; 375 } 376 } 377 } 378 379 // Restore input arrays 380 for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) { 381 // No Restriction 382 if (op->inputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 383 CeedEvalMode emode = qf->inputfields[i].emode; 384 if (emode & CEED_EVAL_WEIGHT) { 385 } else { 386 // Active 387 if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) { 388 ierr = CeedVectorRestoreArrayRead(invec, 389 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 390 // Passive 391 } else { 392 ierr = CeedVectorRestoreArrayRead(op->inputfields[i].vec, 393 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 394 } 395 } 396 } else { 397 // Restriction 398 ierr = CeedVectorRestoreArrayRead(opref->evecs[iein], 399 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 400 iein++; 401 } 402 } 403 404 return 0; 405 } 406 407 int CeedOperatorCreate_Ref(CeedOperator op) { 408 CeedOperator_Ref *impl; 409 int ierr; 410 411 ierr = CeedCalloc(1, &impl); CeedChk(ierr); 412 op->data = impl; 413 op->Destroy = CeedOperatorDestroy_Ref; 414 op->Apply = CeedOperatorApply_Ref; 415 return 0; 416 } 417