Beispiel #1
0
PetscErrorCode PCSetUp_MG(PC pc)
{
    PC_MG          *mg        = (PC_MG*)pc->data;
    PC_MG_Levels   **mglevels = mg->levels;
    PetscErrorCode ierr;
    PetscInt       i,n = mglevels[0]->levels;
    PC             cpc;
    PetscBool      preonly,lu,redundant,cholesky,svd,dump = PETSC_FALSE,opsset,use_amat;
    Mat            dA,dB;
    MatStructure   uflag;
    Vec            tvec;
    DM             *dms;
    PetscViewer    viewer = 0;

    PetscFunctionBegin;
    /* FIX: Move this to PCSetFromOptions_MG? */
    if (mg->usedmfornumberoflevels) {
        PetscInt levels;
        ierr = DMGetRefineLevel(pc->dm,&levels);
        CHKERRQ(ierr);
        levels++;
        if (levels > n) { /* the problem is now being solved on a finer grid */
            ierr     = PCMGSetLevels(pc,levels,NULL);
            CHKERRQ(ierr);
            n        = levels;
            ierr     = PCSetFromOptions(pc);
            CHKERRQ(ierr); /* it is bad to call this here, but otherwise will never be called for the new hierarchy */
            mglevels =  mg->levels;
        }
    }
    ierr = KSPGetPC(mglevels[0]->smoothd,&cpc);
    CHKERRQ(ierr);


    /* If user did not provide fine grid operators OR operator was not updated since last global KSPSetOperators() */
    /* so use those from global PC */
    /* Is this what we always want? What if user wants to keep old one? */
    ierr = KSPGetOperatorsSet(mglevels[n-1]->smoothd,NULL,&opsset);
    CHKERRQ(ierr);
    if (opsset) {
        Mat mmat;
        ierr = KSPGetOperators(mglevels[n-1]->smoothd,NULL,&mmat,NULL);
        CHKERRQ(ierr);
        if (mmat == pc->pmat) opsset = PETSC_FALSE;
    }

    if (!opsset) {
        ierr = PCGetUseAmat(pc,&use_amat);
        CHKERRQ(ierr);
        if(use_amat) {
            ierr = PetscInfo(pc,"Using outer operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");
            CHKERRQ(ierr);
            ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->mat,pc->pmat,pc->flag);
            CHKERRQ(ierr);
        }
        else {
            ierr = PetscInfo(pc,"Using matrix (pmat) operators to define finest grid operator \n  because PCMGGetSmoother(pc,nlevels-1,&ksp);KSPSetOperators(ksp,...); was not called.\n");
            CHKERRQ(ierr);
            ierr = KSPSetOperators(mglevels[n-1]->smoothd,pc->pmat,pc->pmat,pc->flag);
            CHKERRQ(ierr);
        }
    }

    /* Skipping this for galerkin==2 (externally managed hierarchy such as ML and GAMG). Cleaner logic here would be great. Wrap ML/GAMG as DMs? */
    if (pc->dm && mg->galerkin != 2 && !pc->setupcalled) {
        /* construct the interpolation from the DMs */
        Mat p;
        Vec rscale;
        ierr     = PetscMalloc(n*sizeof(DM),&dms);
        CHKERRQ(ierr);
        dms[n-1] = pc->dm;
        for (i=n-2; i>-1; i--) {
            DMKSP kdm;
            ierr = DMCoarsen(dms[i+1],MPI_COMM_NULL,&dms[i]);
            CHKERRQ(ierr);
            ierr = KSPSetDM(mglevels[i]->smoothd,dms[i]);
            CHKERRQ(ierr);
            if (mg->galerkin) {
                ierr = KSPSetDMActive(mglevels[i]->smoothd,PETSC_FALSE);
                CHKERRQ(ierr);
            }
            ierr = DMGetDMKSPWrite(dms[i],&kdm);
            CHKERRQ(ierr);
            /* Ugly hack so that the next KSPSetUp() will use the RHS that we set. A better fix is to change dmActive to take
             * a bitwise OR of computing the matrix, RHS, and initial iterate. */
            kdm->ops->computerhs = NULL;
            kdm->rhsctx          = NULL;
            if (!mglevels[i+1]->interpolate) {
                ierr = DMCreateInterpolation(dms[i],dms[i+1],&p,&rscale);
                CHKERRQ(ierr);
                ierr = PCMGSetInterpolation(pc,i+1,p);
                CHKERRQ(ierr);
                if (rscale) {
                    ierr = PCMGSetRScale(pc,i+1,rscale);
                    CHKERRQ(ierr);
                }
                ierr = VecDestroy(&rscale);
                CHKERRQ(ierr);
                ierr = MatDestroy(&p);
                CHKERRQ(ierr);
            }
        }

        for (i=n-2; i>-1; i--) {
            ierr = DMDestroy(&dms[i]);
            CHKERRQ(ierr);
        }
        ierr = PetscFree(dms);
        CHKERRQ(ierr);
    }

    if (pc->dm && !pc->setupcalled) {
        /* finest smoother also gets DM but it is not active, independent of whether galerkin==2 */
        ierr = KSPSetDM(mglevels[n-1]->smoothd,pc->dm);
        CHKERRQ(ierr);
        ierr = KSPSetDMActive(mglevels[n-1]->smoothd,PETSC_FALSE);
        CHKERRQ(ierr);
    }

    if (mg->galerkin == 1) {
        Mat B;
        /* currently only handle case where mat and pmat are the same on coarser levels */
        ierr = KSPGetOperators(mglevels[n-1]->smoothd,&dA,&dB,&uflag);
        CHKERRQ(ierr);
        if (!pc->setupcalled) {
            for (i=n-2; i>-1; i--) {
                ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_INITIAL_MATRIX,1.0,&B);
                CHKERRQ(ierr);
                ierr = KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);
                CHKERRQ(ierr);
                if (i != n-2) {
                    ierr = PetscObjectDereference((PetscObject)dB);
                    CHKERRQ(ierr);
                }
                dB = B;
            }
            if (n > 1) {
                ierr = PetscObjectDereference((PetscObject)dB);
                CHKERRQ(ierr);
            }
        } else {
            for (i=n-2; i>-1; i--) {
                ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&B,NULL);
                CHKERRQ(ierr);
                ierr = MatPtAP(dB,mglevels[i+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);
                CHKERRQ(ierr);
                ierr = KSPSetOperators(mglevels[i]->smoothd,B,B,uflag);
                CHKERRQ(ierr);
                dB   = B;
            }
        }
    } else if (!mg->galerkin && pc->dm && pc->dm->x) {
        /* need to restrict Jacobian location to coarser meshes for evaluation */
        for (i=n-2; i>-1; i--) {
            Mat R;
            Vec rscale;
            if (!mglevels[i]->smoothd->dm->x) {
                Vec *vecs;
                ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vecs,0,NULL);
                CHKERRQ(ierr);

                mglevels[i]->smoothd->dm->x = vecs[0];

                ierr = PetscFree(vecs);
                CHKERRQ(ierr);
            }
            ierr = PCMGGetRestriction(pc,i+1,&R);
            CHKERRQ(ierr);
            ierr = PCMGGetRScale(pc,i+1,&rscale);
            CHKERRQ(ierr);
            ierr = MatRestrict(R,mglevels[i+1]->smoothd->dm->x,mglevels[i]->smoothd->dm->x);
            CHKERRQ(ierr);
            ierr = VecPointwiseMult(mglevels[i]->smoothd->dm->x,mglevels[i]->smoothd->dm->x,rscale);
            CHKERRQ(ierr);
        }
    }
    if (!mg->galerkin && pc->dm) {
        for (i=n-2; i>=0; i--) {
            DM  dmfine,dmcoarse;
            Mat Restrict,Inject;
            Vec rscale;
            ierr   = KSPGetDM(mglevels[i+1]->smoothd,&dmfine);
            CHKERRQ(ierr);
            ierr   = KSPGetDM(mglevels[i]->smoothd,&dmcoarse);
            CHKERRQ(ierr);
            ierr   = PCMGGetRestriction(pc,i+1,&Restrict);
            CHKERRQ(ierr);
            ierr   = PCMGGetRScale(pc,i+1,&rscale);
            CHKERRQ(ierr);
            Inject = NULL;      /* Callback should create it if it needs Injection */
            ierr   = DMRestrict(dmfine,Restrict,rscale,Inject,dmcoarse);
            CHKERRQ(ierr);
        }
    }

    if (!pc->setupcalled) {
        for (i=0; i<n; i++) {
            ierr = KSPSetFromOptions(mglevels[i]->smoothd);
            CHKERRQ(ierr);
        }
        for (i=1; i<n; i++) {
            if (mglevels[i]->smoothu && (mglevels[i]->smoothu != mglevels[i]->smoothd)) {
                ierr = KSPSetFromOptions(mglevels[i]->smoothu);
                CHKERRQ(ierr);
            }
        }
        for (i=1; i<n; i++) {
            ierr = PCMGGetInterpolation(pc,i,&mglevels[i]->interpolate);
            CHKERRQ(ierr);
            ierr = PCMGGetRestriction(pc,i,&mglevels[i]->restrct);
            CHKERRQ(ierr);
        }
        for (i=0; i<n-1; i++) {
            if (!mglevels[i]->b) {
                Vec *vec;
                ierr = KSPGetVecs(mglevels[i]->smoothd,1,&vec,0,NULL);
                CHKERRQ(ierr);
                ierr = PCMGSetRhs(pc,i,*vec);
                CHKERRQ(ierr);
                ierr = VecDestroy(vec);
                CHKERRQ(ierr);
                ierr = PetscFree(vec);
                CHKERRQ(ierr);
            }
            if (!mglevels[i]->r && i) {
                ierr = VecDuplicate(mglevels[i]->b,&tvec);
                CHKERRQ(ierr);
                ierr = PCMGSetR(pc,i,tvec);
                CHKERRQ(ierr);
                ierr = VecDestroy(&tvec);
                CHKERRQ(ierr);
            }
            if (!mglevels[i]->x) {
                ierr = VecDuplicate(mglevels[i]->b,&tvec);
                CHKERRQ(ierr);
                ierr = PCMGSetX(pc,i,tvec);
                CHKERRQ(ierr);
                ierr = VecDestroy(&tvec);
                CHKERRQ(ierr);
            }
        }
        if (n != 1 && !mglevels[n-1]->r) {
            /* PCMGSetR() on the finest level if user did not supply it */
            Vec *vec;
            ierr = KSPGetVecs(mglevels[n-1]->smoothd,1,&vec,0,NULL);
            CHKERRQ(ierr);
            ierr = PCMGSetR(pc,n-1,*vec);
            CHKERRQ(ierr);
            ierr = VecDestroy(vec);
            CHKERRQ(ierr);
            ierr = PetscFree(vec);
            CHKERRQ(ierr);
        }
    }

    if (pc->dm) {
        /* need to tell all the coarser levels to rebuild the matrix using the DM for that level */
        for (i=0; i<n-1; i++) {
            if (mglevels[i]->smoothd->setupstage != KSP_SETUP_NEW) mglevels[i]->smoothd->setupstage = KSP_SETUP_NEWMATRIX;
        }
    }

    for (i=1; i<n; i++) {
        if (mglevels[i]->smoothu == mglevels[i]->smoothd) {
            /* if doing only down then initial guess is zero */
            ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothd,PETSC_TRUE);
            CHKERRQ(ierr);
        }
        if (mglevels[i]->eventsmoothsetup) {
            ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);
            CHKERRQ(ierr);
        }
        ierr = KSPSetUp(mglevels[i]->smoothd);
        CHKERRQ(ierr);
        if (mglevels[i]->eventsmoothsetup) {
            ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);
            CHKERRQ(ierr);
        }
        if (!mglevels[i]->residual) {
            Mat mat;
            ierr = KSPGetOperators(mglevels[i]->smoothd,NULL,&mat,NULL);
            CHKERRQ(ierr);
            ierr = PCMGSetResidual(pc,i,PCMGResidual_Default,mat);
            CHKERRQ(ierr);
        }
    }
    for (i=1; i<n; i++) {
        if (mglevels[i]->smoothu && mglevels[i]->smoothu != mglevels[i]->smoothd) {
            Mat          downmat,downpmat;
            MatStructure matflag;

            /* check if operators have been set for up, if not use down operators to set them */
            ierr = KSPGetOperatorsSet(mglevels[i]->smoothu,&opsset,NULL);
            CHKERRQ(ierr);
            if (!opsset) {
                ierr = KSPGetOperators(mglevels[i]->smoothd,&downmat,&downpmat,&matflag);
                CHKERRQ(ierr);
                ierr = KSPSetOperators(mglevels[i]->smoothu,downmat,downpmat,matflag);
                CHKERRQ(ierr);
            }

            ierr = KSPSetInitialGuessNonzero(mglevels[i]->smoothu,PETSC_TRUE);
            CHKERRQ(ierr);
            if (mglevels[i]->eventsmoothsetup) {
                ierr = PetscLogEventBegin(mglevels[i]->eventsmoothsetup,0,0,0,0);
                CHKERRQ(ierr);
            }
            ierr = KSPSetUp(mglevels[i]->smoothu);
            CHKERRQ(ierr);
            if (mglevels[i]->eventsmoothsetup) {
                ierr = PetscLogEventEnd(mglevels[i]->eventsmoothsetup,0,0,0,0);
                CHKERRQ(ierr);
            }
        }
    }

    /*
        If coarse solver is not direct method then DO NOT USE preonly
    */
    ierr = PetscObjectTypeCompare((PetscObject)mglevels[0]->smoothd,KSPPREONLY,&preonly);
    CHKERRQ(ierr);
    if (preonly) {
        ierr = PetscObjectTypeCompare((PetscObject)cpc,PCLU,&lu);
        CHKERRQ(ierr);
        ierr = PetscObjectTypeCompare((PetscObject)cpc,PCREDUNDANT,&redundant);
        CHKERRQ(ierr);
        ierr = PetscObjectTypeCompare((PetscObject)cpc,PCCHOLESKY,&cholesky);
        CHKERRQ(ierr);
        ierr = PetscObjectTypeCompare((PetscObject)cpc,PCSVD,&svd);
        CHKERRQ(ierr);
        if (!lu && !redundant && !cholesky && !svd) {
            ierr = KSPSetType(mglevels[0]->smoothd,KSPGMRES);
            CHKERRQ(ierr);
        }
    }

    if (!pc->setupcalled) {
        ierr = KSPSetFromOptions(mglevels[0]->smoothd);
        CHKERRQ(ierr);
    }

    if (mglevels[0]->eventsmoothsetup) {
        ierr = PetscLogEventBegin(mglevels[0]->eventsmoothsetup,0,0,0,0);
        CHKERRQ(ierr);
    }
    ierr = KSPSetUp(mglevels[0]->smoothd);
    CHKERRQ(ierr);
    if (mglevels[0]->eventsmoothsetup) {
        ierr = PetscLogEventEnd(mglevels[0]->eventsmoothsetup,0,0,0,0);
        CHKERRQ(ierr);
    }

    /*
       Dump the interpolation/restriction matrices plus the
     Jacobian/stiffness on each level. This allows MATLAB users to
     easily check if the Galerkin condition A_c = R A_f R^T is satisfied.

     Only support one or the other at the same time.
    */
#if defined(PETSC_USE_SOCKET_VIEWER)
    ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_mg_dump_matlab",&dump,NULL);
    CHKERRQ(ierr);
    if (dump) viewer = PETSC_VIEWER_SOCKET_(PetscObjectComm((PetscObject)pc));
    dump = PETSC_FALSE;
#endif
    ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_mg_dump_binary",&dump,NULL);
    CHKERRQ(ierr);
    if (dump) viewer = PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)pc));

    if (viewer) {
        for (i=1; i<n; i++) {
            ierr = MatView(mglevels[i]->restrct,viewer);
            CHKERRQ(ierr);
        }
        for (i=0; i<n; i++) {
            ierr = KSPGetPC(mglevels[i]->smoothd,&pc);
            CHKERRQ(ierr);
            ierr = MatView(pc->mat,viewer);
            CHKERRQ(ierr);
        }
    }
    PetscFunctionReturn(0);
}
Beispiel #2
0
/*@C
   PetscOptionsGetViewer - Gets a viewer appropriate for the type indicated by the user

   Collective on MPI_Comm

   Input Parameters:
+  comm - the communicator to own the viewer
.  pre - the string to prepend to the name or NULL
-  name - the option one is seeking

   Output Parameter:
+  viewer - the viewer, pass NULL if not needed
.  format - the PetscViewerFormat requested by the user, pass NULL if not needed
-  set - PETSC_TRUE if found, else PETSC_FALSE

   Level: intermediate

   Notes: If no value is provided ascii:stdout is used
$       ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab, 
                                                  for example ascii::ascii_info prints just the information about the object not all details
                                                  unless :append is given filename opens in write mode, overwriting what was already there
$       binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
$       draw[:drawtype]                           for example, draw:tikz  or draw:x
$       socket[:port]                             defaults to the standard output port
$       saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)

   Use PetscViewerDestroy() after using the viewer, otherwise a memory leak will occur

.seealso: PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
          PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
          PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
          PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
          PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
          PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
          PetscOptionsFList(), PetscOptionsEList()
@*/
PetscErrorCode  PetscOptionsGetViewer(MPI_Comm comm,const char pre[],const char name[],PetscViewer *viewer,PetscViewerFormat *format,PetscBool  *set)
{
  char           *value;
  PetscErrorCode ierr;
  PetscBool      flag,hashelp;

  PetscFunctionBegin;
  PetscValidCharPointer(name,3);

  ierr = PetscOptionsHasName(NULL,"-help",&hashelp);CHKERRQ(ierr);
  if (hashelp) {
    ierr = (*PetscHelpPrintf)(comm,"  -%s%s ascii[:[filename][:[format][:append]]]: %s (%s)\n",pre ? pre : "",name+1,"Triggers display of a PETSc object to screen or ASCII file","PetscOptionsGetViewer");CHKERRQ(ierr);
    ierr = (*PetscHelpPrintf)(comm,"  -%s%s binary[:[filename][:[format][:append]]]: %s (%s)\n",pre ? pre : "",name+1,"Triggers saving of a PETSc object to a binary file","PetscOptionsGetViewer");CHKERRQ(ierr);
    ierr = (*PetscHelpPrintf)(comm,"  -%s%s draw[:drawtype]: %s (%s)\n",pre ? pre : "",name+1,"Triggers drawing of a PETSc object","PetscOptionsGetViewer");CHKERRQ(ierr);
    ierr = (*PetscHelpPrintf)(comm,"  -%s%s socket[:port]: %s (%s)\n",pre ? pre : "",name+1,"Triggers push of a PETSc object to a Unix socket","PetscOptionsGetViewer");CHKERRQ(ierr);
    ierr = (*PetscHelpPrintf)(comm,"  -%s%s saws[:communicatorname]: %s (%s)\n",pre ? pre : "",name+1,"Triggers publishing of a PETSc object to SAWs","PetscOptionsGetViewer");CHKERRQ(ierr);
  }

  if (format) *format = PETSC_VIEWER_DEFAULT;
  if (set) *set = PETSC_FALSE;
  ierr = PetscOptionsFindPair_Private(pre,name,&value,&flag);CHKERRQ(ierr);
  if (flag) {
    if (set) *set = PETSC_TRUE;
    if (!value) {
      if (viewer) {
        ierr = PetscViewerASCIIGetStdout(comm,viewer);CHKERRQ(ierr);
        ierr = PetscObjectReference((PetscObject)*viewer);CHKERRQ(ierr);
      }
    } else {
      char       *loc0_vtype,*loc1_fname,*loc2_fmt = NULL,*loc3_fmode = NULL;
      PetscInt   cnt;
      const char *viewers[] = {PETSCVIEWERASCII,PETSCVIEWERBINARY,PETSCVIEWERDRAW,PETSCVIEWERSOCKET,PETSCVIEWERMATLAB,PETSCVIEWERSAWS,PETSCVIEWERVTK,PETSCVIEWERHDF5,0};

      ierr = PetscStrallocpy(value,&loc0_vtype);CHKERRQ(ierr);
      ierr = PetscStrchr(loc0_vtype,':',&loc1_fname);CHKERRQ(ierr);
      if (loc1_fname) {
        *loc1_fname++ = 0;
        ierr = PetscStrchr(loc1_fname,':',&loc2_fmt);CHKERRQ(ierr);
      }
      if (loc2_fmt) {
        *loc2_fmt++ = 0;
        ierr = PetscStrchr(loc2_fmt,':',&loc3_fmode);CHKERRQ(ierr);
      }
      if (loc3_fmode) *loc3_fmode++ = 0;
      ierr = PetscStrendswithwhich(*loc0_vtype ? loc0_vtype : "ascii",viewers,&cnt);CHKERRQ(ierr);
      if (cnt > (PetscInt) sizeof(viewers)-1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Unknown viewer type: %s",loc0_vtype);
      if (viewer) {
        if (!loc1_fname) {
          switch (cnt) {
          case 0:
            ierr = PetscViewerASCIIGetStdout(comm,viewer);CHKERRQ(ierr);
            break;
          case 1:
            if (!(*viewer = PETSC_VIEWER_BINARY_(comm))) CHKERRQ(PETSC_ERR_PLIB);
            break;
          case 2:
            if (!(*viewer = PETSC_VIEWER_DRAW_(comm))) CHKERRQ(PETSC_ERR_PLIB);
            break;
#if defined(PETSC_USE_SOCKET_VIEWER)
          case 3:
            if (!(*viewer = PETSC_VIEWER_SOCKET_(comm))) CHKERRQ(PETSC_ERR_PLIB);
            break;
#endif
#if defined(PETSC_HAVE_MATLAB_ENGINE)
          case 4:
            if (!(*viewer = PETSC_VIEWER_MATLAB_(comm))) CHKERRQ(PETSC_ERR_PLIB);
            break;
#endif
#if defined(PETSC_HAVE_SAWS)
          case 5:
            if (!(*viewer = PETSC_VIEWER_SAWS_(comm))) CHKERRQ(PETSC_ERR_PLIB);
            break;
#endif
#if defined(PETSC_HAVE_HDF5)
          case 7:
            if (!(*viewer = PETSC_VIEWER_HDF5_(comm))) CHKERRQ(PETSC_ERR_PLIB);
            break;
#endif
          default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported viewer %s",loc0_vtype);
          }
          ierr = PetscObjectReference((PetscObject)*viewer);CHKERRQ(ierr);
        } else {
          if (loc2_fmt && !*loc1_fname && (cnt == 0)) { /* ASCII format without file name */
            ierr = PetscViewerASCIIGetStdout(comm,viewer);CHKERRQ(ierr);
            ierr = PetscObjectReference((PetscObject)*viewer);CHKERRQ(ierr);
          } else {
            PetscFileMode fmode;
            ierr = PetscViewerCreate(comm,viewer);CHKERRQ(ierr);
            ierr = PetscViewerSetType(*viewer,*loc0_vtype ? loc0_vtype : "ascii");CHKERRQ(ierr);
            fmode = FILE_MODE_WRITE;
            if (loc3_fmode && *loc3_fmode) { /* Has non-empty file mode ("write" or "append") */
              ierr = PetscEnumFind(PetscFileModes,loc3_fmode,(PetscEnum*)&fmode,&flag);CHKERRQ(ierr);
              if (!flag) SETERRQ1(comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown file mode: %s",loc3_fmode);
            }
            ierr = PetscViewerFileSetMode(*viewer,flag?fmode:FILE_MODE_WRITE);CHKERRQ(ierr);
            ierr = PetscViewerFileSetName(*viewer,loc1_fname);CHKERRQ(ierr);
            ierr = PetscViewerDrawSetDrawType(*viewer,loc1_fname);CHKERRQ(ierr);
          }
        }
      }
      if (viewer) {
        ierr = PetscViewerSetUp(*viewer);CHKERRQ(ierr);
      }
      if (loc2_fmt && *loc2_fmt) {
        ierr = PetscEnumFind(PetscViewerFormats,loc2_fmt,(PetscEnum*)format,&flag);CHKERRQ(ierr);
        if (!flag) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unknown viewer format %s",loc2_fmt);CHKERRQ(ierr);
      }
      ierr = PetscFree(loc0_vtype);CHKERRQ(ierr);
    }
  }
  PetscFunctionReturn(0);
}