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, 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 != CEED_RESTRICTION_IDENTITY); // Need E-vector when non-identity restriction exists 114 } 115 for (CeedInt i=0; i<qf->numoutputfields; i++) { 116 CeedEvalMode emode = qf->outputfields[i].emode; 117 opref->numqout += !!(emode & CEED_EVAL_INTERP) + !!(emode & CEED_EVAL_GRAD); 118 opref->numeout += (op->outputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY); 119 } 120 121 // Allocate 122 ierr = CeedCalloc(opref->numein + opref->numeout, &opref->evecs); CeedChk(ierr); 123 ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->edata); 124 CeedChk(ierr); 125 126 ierr = CeedCalloc(opref->numqin + opref->numqout, &opref->qdata_alloc); 127 CeedChk(ierr); 128 ierr = CeedCalloc(qf->numinputfields + qf->numoutputfields, &opref->qdata); 129 CeedChk(ierr); 130 131 ierr = CeedCalloc(16, &opref->indata); CeedChk(ierr); 132 ierr = CeedCalloc(16, &opref->outdata); CeedChk(ierr); 133 134 // Set up infield and outfield pointer arrays 135 // Infields 136 ierr = CeedOperatorSetupFields_Ref(qf->inputfields, op->inputfields, 137 opref->evecs, opref->qdata, opref->qdata_alloc, 138 opref->indata, 0, 0, 0, 139 qf->numinputfields, Q); CeedChk(ierr); 140 141 // Outfields 142 ierr = CeedOperatorSetupFields_Ref(qf->outputfields, op->outputfields, 143 opref->evecs, opref->qdata, opref->qdata_alloc, 144 opref->indata, qf->numinputfields, opref->numein, 145 opref->numqin, qf->numoutputfields, Q); CeedChk(ierr); 146 147 // Output Qvecs 148 for (CeedInt i=0; i<qf->numoutputfields; i++) { 149 CeedEvalMode emode = qf->outputfields[i].emode; 150 if (emode != CEED_EVAL_NONE) { 151 opref->outdata[i] = opref->qdata[i + qf->numinputfields]; 152 } 153 } 154 155 op->setupdone = 1; 156 157 return 0; 158 } 159 160 static int CeedOperatorApply_Ref(CeedOperator op, CeedVector invec, 161 CeedVector outvec, CeedRequest *request) { 162 CeedOperator_Ref *opref = op->data; 163 CeedInt Q = op->numqpoints, elemsize; 164 int ierr; 165 CeedQFunction qf = op->qf; 166 CeedTransposeMode lmode = CEED_NOTRANSPOSE; 167 CeedScalar *vec_temp; 168 169 // Setup 170 ierr = CeedOperatorSetup_Ref(op); CeedChk(ierr); 171 172 // Input Evecs and Restriction 173 for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) { 174 // No Restriction 175 if (op->inputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 176 CeedEvalMode emode = qf->inputfields[i].emode; 177 if (emode & CEED_EVAL_WEIGHT) { 178 } else { 179 // Active 180 if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) { 181 ierr = CeedVectorGetArrayRead(invec, CEED_MEM_HOST, 182 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 183 // Passive 184 } else { 185 ierr = CeedVectorGetArrayRead(op->inputfields[i].vec, CEED_MEM_HOST, 186 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 187 } 188 } 189 } else { 190 // Restriction 191 // Zero evec 192 ierr = CeedVectorGetArray(opref->evecs[iein], CEED_MEM_HOST, &vec_temp); 193 CeedChk(ierr); 194 for (CeedInt j=0; j<opref->evecs[iein]->length; j++) 195 vec_temp[j] = 0.; 196 ierr = CeedVectorRestoreArray(opref->evecs[iein], &vec_temp); CeedChk(ierr); 197 // Active 198 if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) { 199 // Restrict 200 ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE, 201 lmode, invec, opref->evecs[iein], 202 request); CeedChk(ierr); 203 // Get evec 204 ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST, 205 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 206 iein++; 207 } else { 208 // Passive 209 // Restrict 210 ierr = CeedElemRestrictionApply(op->inputfields[i].Erestrict, CEED_NOTRANSPOSE, 211 lmode, op->inputfields[i].vec, opref->evecs[iein], 212 request); CeedChk(ierr); 213 // Get evec 214 ierr = CeedVectorGetArrayRead(opref->evecs[iein], CEED_MEM_HOST, 215 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 216 iein++; 217 } 218 } 219 } 220 221 // Output Evecs 222 for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) { 223 // No Restriction 224 if (op->outputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 225 // Active 226 if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) { 227 ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST, 228 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 229 } else { 230 // Passive 231 ierr = CeedVectorGetArray(op->outputfields[i].vec, CEED_MEM_HOST, 232 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 233 } 234 } else { 235 // Restriction 236 ierr = CeedVectorGetArray(opref->evecs[ieout], CEED_MEM_HOST, 237 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 238 ieout++; 239 } 240 } 241 242 // Loop through elements 243 for (CeedInt e=0; e<op->numelements; e++) { 244 // Input basis apply if needed 245 for (CeedInt i=0; i<qf->numinputfields; i++) { 246 // Get elemsize 247 if (op->inputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY) { 248 elemsize = op->inputfields[i].Erestrict->elemsize; 249 } else { 250 elemsize = Q; 251 } 252 // Get emode, ncomp 253 CeedEvalMode emode = qf->inputfields[i].emode; 254 CeedInt ncomp = qf->inputfields[i].ncomp; 255 // Basis action 256 switch(emode) { 257 case CEED_EVAL_NONE: 258 opref->indata[i] = &opref->edata[i][e*Q*ncomp]; 259 break; 260 case CEED_EVAL_INTERP: 261 ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE, 262 CEED_EVAL_INTERP, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]); 263 CeedChk(ierr); 264 opref->indata[i] = opref->qdata[i]; 265 break; 266 case CEED_EVAL_GRAD: 267 ierr = CeedBasisApply(op->inputfields[i].basis, CEED_NOTRANSPOSE, 268 CEED_EVAL_GRAD, &opref->edata[i][e*elemsize*ncomp], opref->qdata[i]); 269 CeedChk(ierr); 270 opref->indata[i] = opref->qdata[i]; 271 break; 272 case CEED_EVAL_WEIGHT: 273 break; // No action 274 case CEED_EVAL_DIV: 275 break; // Not implimented 276 case CEED_EVAL_CURL: 277 break; // Not implimented 278 } 279 } 280 // Output pointers 281 for (CeedInt i=0; i<qf->numoutputfields; i++) { 282 CeedEvalMode emode = qf->outputfields[i].emode; 283 if (emode == CEED_EVAL_NONE) { 284 CeedInt ncomp = qf->outputfields[i].ncomp; 285 opref->outdata[i] = &opref->edata[i + qf->numinputfields][e*Q*ncomp]; 286 } 287 } 288 // Q function 289 ierr = CeedQFunctionApply(op->qf, Q, (const CeedScalar * const*) opref->indata, 290 opref->outdata); CeedChk(ierr); 291 292 // Output basis apply if needed 293 for (CeedInt i=0; i<qf->numoutputfields; i++) { 294 // Get elemsize 295 if (op->outputfields[i].Erestrict != CEED_RESTRICTION_IDENTITY) { 296 elemsize = op->outputfields[i].Erestrict->elemsize; 297 } else { 298 elemsize = Q; 299 } 300 // Get emode, ncomp 301 CeedInt ncomp = qf->outputfields[i].ncomp; 302 CeedEvalMode emode = qf->outputfields[i].emode; 303 // Basis action 304 switch(emode) { 305 case CEED_EVAL_NONE: 306 break; // No action 307 case CEED_EVAL_INTERP: 308 ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE, 309 CEED_EVAL_INTERP, opref->outdata[i], 310 &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); CeedChk(ierr); 311 break; 312 case CEED_EVAL_GRAD: 313 ierr = CeedBasisApply(op->outputfields[i].basis, CEED_TRANSPOSE, CEED_EVAL_GRAD, 314 opref->outdata[i], &opref->edata[i + qf->numinputfields][e*elemsize*ncomp]); 315 CeedChk(ierr); 316 break; 317 case CEED_EVAL_WEIGHT: 318 break; // Should not occur 319 case CEED_EVAL_DIV: 320 break; // Not implimented 321 case CEED_EVAL_CURL: 322 break; // Not implimented 323 } 324 } 325 } 326 327 // Output restriction 328 for (CeedInt i=0,ieout=opref->numein; i<qf->numoutputfields; i++) { 329 // No Restriction 330 if (op->outputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 331 // Active 332 if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) { 333 ierr = CeedVectorRestoreArray(outvec, &opref->edata[i + qf->numinputfields]); 334 CeedChk(ierr); 335 } else { 336 // Passive 337 ierr = CeedVectorRestoreArray(op->outputfields[i].vec, 338 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 339 } 340 } else { 341 // Restriction 342 // Active 343 if (op->outputfields[i].vec == CEED_VECTOR_ACTIVE) { 344 // Restore evec 345 ierr = CeedVectorRestoreArray(opref->evecs[ieout], 346 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 347 // Zero lvec 348 ierr = CeedVectorGetArray(outvec, CEED_MEM_HOST, &vec_temp); CeedChk(ierr); 349 for (CeedInt j=0; j<outvec->length; j++) 350 vec_temp[j] = 0.; 351 ierr = CeedVectorRestoreArray(outvec, &vec_temp); CeedChk(ierr); 352 // Restrict 353 ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE, 354 lmode, opref->evecs[ieout], outvec, request); CeedChk(ierr); 355 ieout++; 356 } else { 357 // Passive 358 // Restore evec 359 ierr = CeedVectorRestoreArray(opref->evecs[ieout], 360 &opref->edata[i + qf->numinputfields]); CeedChk(ierr); 361 // Zero lvec 362 ierr = CeedVectorGetArray(op->outputfields[i].vec, CEED_MEM_HOST, &vec_temp); 363 CeedChk(ierr); 364 for (CeedInt j=0; j<op->outputfields[i].vec->length; j++) 365 vec_temp[j] = 0.; 366 ierr = CeedVectorRestoreArray(op->outputfields[i].vec, &vec_temp); 367 CeedChk(ierr); 368 // Restrict 369 ierr = CeedElemRestrictionApply(op->outputfields[i].Erestrict, CEED_TRANSPOSE, 370 lmode, opref->evecs[ieout], op->outputfields[i].vec, 371 request); CeedChk(ierr); 372 ieout++; 373 } 374 } 375 } 376 377 // Restore input arrays 378 for (CeedInt i=0,iein=0; i<qf->numinputfields; i++) { 379 // No Restriction 380 if (op->inputfields[i].Erestrict == CEED_RESTRICTION_IDENTITY) { 381 CeedEvalMode emode = qf->inputfields[i].emode; 382 if (emode & CEED_EVAL_WEIGHT) { 383 } else { 384 // Active 385 if (op->inputfields[i].vec == CEED_VECTOR_ACTIVE) { 386 ierr = CeedVectorRestoreArrayRead(invec, 387 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 388 // Passive 389 } else { 390 ierr = CeedVectorRestoreArrayRead(op->inputfields[i].vec, 391 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 392 } 393 } 394 } else { 395 // Restriction 396 ierr = CeedVectorRestoreArrayRead(opref->evecs[iein], 397 (const CeedScalar **) &opref->edata[i]); CeedChk(ierr); 398 iein++; 399 } 400 } 401 402 return 0; 403 } 404 405 int CeedOperatorCreate_Ref(CeedOperator op) { 406 CeedOperator_Ref *impl; 407 int ierr; 408 409 ierr = CeedCalloc(1, &impl); CeedChk(ierr); 410 op->data = impl; 411 op->Destroy = CeedOperatorDestroy_Ref; 412 op->Apply = CeedOperatorApply_Ref; 413 return 0; 414 } 415