示例#1
0
void RisingFactorialCache::Init(int num_already, double hyper) {
  num_already_ = num_already;
  hyper_ = hyper;
  SetInitialValues();
}
示例#2
0
文件: main.c 项目: Oblomov/mandelbrot
int main(void)
{
	printf("\n"
	       "Controls:  - Left/Right Click to zoom in/out, centring on cursor position.\n"
	       "           - Left Click and Drag to pan.\n"
	       "           - r to reset view.\n"
	       "           - q,w to decrease, increase max iteration count\n"
	       "           - a,s to decrease, increase colour period\n"
	       "           - g to toggle Gaussian Blur after computation\n"
	       "           - b to run some benchmarks.\n"
	       "           - p to show a double-precision limited zoom.\n"
	       "           - h to save a high resolution image of the current view to current directory.\n"
	       "           - Esc to quit.\n\n");

	// Set render function, dependent on compile time flag. All have the same signature,
	// with all necessary variables defined inside the structs.
#ifdef WITHOPENCL
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotOpenCL;
#elif defined(WITHAVX)
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotAVXCPU;
	// AVX double prec vector width (4) must divide horizontal (x) resolution
	assert(XRESOLUTION % 4 == 0);
#elif defined(WITHGMP)
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotGMPCPU;
#else
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotCPU;
#endif


	// Define and initialize structs
	imageStruct image;
	renderStruct render;
	// Set image resolution
	image.xRes = XRESOLUTION;
	image.yRes = YRESOLUTION;
	// Initial values for boundaries, iteration count
	SetInitialValues(&image);
	// Update OpenGL texture on render. This is disabled when rendering high resolution images
	render.updateTex = 1;
	// Allocate host memory, used to set up OpenGL texture, even if we are using interop OpenCL
	image.pixels = malloc(image.xRes * image.yRes * sizeof *(image.pixels) *3);


	// OpenGL variables and setup
	render.window = NULL;
	GLuint vertexShader, fragmentShader, shaderProgram;
	GLuint vao, vbo, ebo, tex;
	SetUpOpenGL(&(render.window), image.xRes, image.yRes, &vertexShader, &fragmentShader, &shaderProgram, &vao, &vbo, &ebo, &tex);


#ifdef WITHOPENCL
	// OpenCL variables and setup
	cl_platform_id    *platform;
	cl_device_id      **device_id;
	cl_program        program;
	cl_int            err;
	render.globalSize = image.xRes * image.yRes;
	render.localSize = OPENCLLOCALSIZE;
	assert(render.globalSize % render.localSize == 0);

	// Initially set variable that controls interop of OpenGL and OpenCL to 0, set to 1 if
	// interop device found successfully
	render.glclInterop = 0;

	if (InitialiseCLEnvironment(&platform, &device_id, &program, &render) == EXIT_FAILURE) {
		printf("Error initialising OpenCL environment\n");
		return EXIT_FAILURE;
	}
	size_t sizeBytes = image.xRes * image.yRes * 3 * sizeof(float);
	render.pixelsDevice = clCreateBuffer(render.contextCL, CL_MEM_READ_WRITE, sizeBytes, NULL, &err);
	// if we aren't using interop, allocate another buffer on the device for output, on the pointer
	// for the texture
	if (render.glclInterop == 0) {
		render.pixelsTex = clCreateBuffer(render.contextCL, CL_MEM_READ_WRITE, sizeBytes, NULL, &err);
	}

	// finish texture initialization so that we can use with OpenCL if glclInterop
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.xRes, image.yRes, 0, GL_RGB, GL_FLOAT, image.pixels);
	// Configure image from OpenGL texture "tex"
	if (render.glclInterop) {
		render.pixelsTex = clCreateFromGLTexture(render.contextCL, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, tex, &err);
		CheckOpenCLError(err, __LINE__);
	}


	// Create kernels
	render.renderMandelbrotKernel = clCreateKernel(program, "renderMandelbrotKernel", &err);
	CheckOpenCLError(err, __LINE__);
	render.gaussianBlurKernel = clCreateKernel(program, "gaussianBlurKernel", &err);
	CheckOpenCLError(err, __LINE__);
	render.gaussianBlurKernel2 = clCreateKernel(program, "gaussianBlurKernel2", &err);
	CheckOpenCLError(err, __LINE__);
#endif


	// Start main loop: Update until we encounter user input. Look for Esc key (quit), left and right mount
	// buttons (zoom in on cursor position, zoom out on cursor position), "r" -- reset back to initial coords,
	// "b" -- run some benchmarks, "p" -- display a double precision limited zoom.
	// Re-render the Mandelbrot set as and when we need, in the user input conditionals.

	// Initial render:
	RenderMandelbrot(&render, &image);

	while (!glfwWindowShouldClose(render.window)) {

		// draw
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		// Swap buffers
		glfwSwapBuffers(render.window);


		// USER INPUT TESTS.
		// Continuous render, poll for input:
		//glfwPollEvents();
		// Render only on update, wait for input:
		glfwWaitEvents();


		// if user presses Esc, close window to leave loop
		if (glfwGetKey(render.window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		    glfwSetWindowShouldClose(render.window, GL_TRUE);
		}


		// if user left-clicks in window, zoom in, centring on cursor position
		// if click and drag, simply re-position centre without zooming
		else if (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {

			// Get Press cursor location
			double xPressPos, yPressPos, xReleasePos, yReleasePos;
			int shift = 0;
			glfwGetCursorPos(render.window, &xPressPos, &yPressPos);

			// Wait for mousebutton release, re-rendering as mouse moves
			while (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_LEFT) != GLFW_RELEASE) {

				glfwGetCursorPos(render.window, &xReleasePos, &yReleasePos);

				if (fabs(xReleasePos-xPressPos) > DRAGPIXELS || fabs(yReleasePos-yPressPos) > DRAGPIXELS) {
					// Set shift variable. Don't zoom after button release if this is 1
					shift = 1;
					// Determine shift in mandelbrot coords
					double xShift = (xReleasePos-xPressPos)/(double)image.xRes*(image.xMax-image.xMin);
					double yShift = (yReleasePos-yPressPos)/(double)image.yRes*(image.yMax-image.yMin);

					// Add shift to boundaries
					image.xMin = image.xMin - xShift;
					image.xMax = image.xMax - xShift;
					image.yMin = image.yMin - yShift;
					image.yMax = image.yMax - yShift;

					// Update "current" (press) position
					xPressPos = xReleasePos;
					yPressPos = yReleasePos;

					// Re-render and draw
					RenderMandelbrot(&render, &image);
					glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
					glfwSwapBuffers(render.window);
				}
				glfwPollEvents();
			}

			// else, zoom in smoothly over ZOOMSTEPS frames
			if (!shift) {
				SmoothZoom(&render, &image, RenderMandelbrot, xReleasePos, yReleasePos, ZOOMFACTOR, ITERSFACTOR);
			}
		}


		// if user right-clicks in window, zoom out, centring on cursor position
		else if (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
			while (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_RIGHT) != GLFW_RELEASE) {
				glfwPollEvents();
			}

			// Get cursor position, in *screen coordinates*
			double xReleasePos, yReleasePos;
			glfwGetCursorPos(render.window, &xReleasePos, &yReleasePos);

			// Zooming out, so use 1/FACTORs.
			SmoothZoom(&render, &image, RenderMandelbrot, xReleasePos, yReleasePos, 1.0/ZOOMFACTOR, 1.0/ITERSFACTOR);
		}


		// if user presses "r", reset view
		else if (glfwGetKey(render.window, GLFW_KEY_R) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_R) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Resetting...\n");
			SetInitialValues(&image);
			RenderMandelbrot(&render, &image);
		}


		// if user presses "g", toggle gaussian blur
		else if (glfwGetKey(render.window, GLFW_KEY_G) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_G) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			if (image.gaussianBlur == 1) {
				printf("Toggling Gaussian Blur Off...\n");
				image.gaussianBlur = 0;
			}
			else {
				printf("Toggling Gaussian Blur On...\n");
				image.gaussianBlur = 1;
			}
			RenderMandelbrot(&render, &image);
		}


		// if user presses "q", decrease max iteration count
		else if (glfwGetKey(render.window, GLFW_KEY_Q) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_Q) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Decreasing max iteration count from %d to %d\n", image.maxIters, (int)(image.maxIters/ITERSFACTOR));
			image.maxIters /= ITERSFACTOR;
			RenderMandelbrot(&render, &image);
		}
		// if user presses "w", increase max iteration count
		else if (glfwGetKey(render.window, GLFW_KEY_W) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_W) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Increasing max iteration count from %d to %d\n", image.maxIters, (int)(image.maxIters*ITERSFACTOR));
			image.maxIters *= ITERSFACTOR;
			RenderMandelbrot(&render, &image);
		}


		// if user presses "a", decrease colour period
		else if (glfwGetKey(render.window, GLFW_KEY_A) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_A) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Decreasing colour period from %.0lf to %.0lf\n", image.colourPeriod, fmax(32, image.colourPeriod-32));
			image.colourPeriod = fmax(32, image.colourPeriod-32);
			RenderMandelbrot(&render, &image);
		}
		// if user presses "s", increase colour period
		else if (glfwGetKey(render.window, GLFW_KEY_S) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_S) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Increasing colour period from %.0lf to %.0lf\n", image.colourPeriod, image.colourPeriod+32);
			image.colourPeriod += 32;
			RenderMandelbrot(&render, &image);
		}


		// if user presses "b", run some benchmarks.
		else if (glfwGetKey(render.window, GLFW_KEY_B) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_B) != GLFW_RELEASE) {
				glfwPollEvents();
			}

			printf("Running Benchmarks...\n");

			printf("Whole fractal:\n");
			SetInitialValues(&image);
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Early Bail-out:\n");
			image.xMin = -0.8153143016681144;
			image.xMax = -0.6839170011300622;
			image.yMin = -0.0365167077914237;
			image.yMax =  0.0373942737612310;
			image.maxIters = 112;
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Spiral:\n");
			image.xMin = -0.8673755781976442;
			image.xMax = -0.8673711898931797;
			image.yMin = -0.2156059883952151;
			image.yMax = -0.2156035199739536;
			image.maxIters = 1757;
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Highly zoomed:\n");
			image.xMin = -0.8712903154956539;
			image.xMax = -0.8712903108993595;
			image.yMin = -0.2293516610223087;
			image.yMax = -0.2293516584368930;
			image.maxIters = 10750;
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Complete.\n");
		// Re-render with original coords
			SetInitialValues(&image);
			RenderMandelbrot(&render, &image);
		}


		// if user presses "p", zoom in, such that the double precision algorithm looks pixellated
		else if (glfwGetKey(render.window, GLFW_KEY_P) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_P) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Precision test...\n");
			image.xMin = -1.25334325335487362;
			image.xMax = -1.25334325335481678;
			image.yMin = -0.34446232396119353;
			image.yMax = -0.34446232396116155;
			image.maxIters = 1389952;
			RenderMandelbrot(&render, &image);
		}


		// if user presses "h", render a high resolution version of the current view, and
		// save it to disk as an image
		else if (glfwGetKey(render.window, GLFW_KEY_H) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_H) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			double startTime = GetWallTime();
			printf("Saving high resolution (%d x %d) image...\n",
			       image.xRes*HIGHRESOLUTIONMULTIPLIER, image.yRes*HIGHRESOLUTIONMULTIPLIER);
			HighResolutionRender(&render, &image, RenderMandelbrot);
			printf("   --- done. Total time: %lfs\n", GetWallTime()-startTime);
		}
	}



	// clean up
#ifdef WITHOPENCL
	CleanUpCLEnvironment(&platform, &device_id, &(render.contextCL), &(render.queue), &program);
#endif

	glDeleteProgram(shaderProgram);
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);
	glDeleteBuffers(1, &ebo);
	glDeleteBuffers(1, &vbo);
	glDeleteVertexArrays(1, &vao);

	// Close OpenGL window and terminate GLFW
	glfwDestroyWindow(render.window);
	glfwTerminate();

	// Free dynamically allocated memory
	free(image.pixels);
	return 0;
}
示例#3
0
void ArrangementProbNumeratorCache::Init(int num_tables_already, double discount, double concentration) {
  num_tables_already_ = num_tables_already;
  discount_ = discount;
  concentration_ = concentration;
  SetInitialValues();
}
示例#4
0
文件: pf.c 项目: plguhur/petsc
int main(int argc,char ** argv)
{
  PetscErrorCode ierr;
  char           pfdata_file[PETSC_MAX_PATH_LEN]="datafiles/case9.m";
  PFDATA         *pfdata;
  PetscInt       numEdges=0,numVertices=0;
  int            *edges = NULL;
  PetscInt       i;  
  DM             networkdm;
  PetscInt       componentkey[4];
  UserCtx        User;
  PetscLogStage  stage1,stage2;
  PetscMPIInt    size;
  PetscInt       eStart, eEnd, vStart, vEnd,j;
  PetscInt       genj,loadj;
  Vec            X,F;
  Mat            J;
  SNES           snes;

  PetscInitialize(&argc,&argv,"pfoptions",help);
  ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);

  /* Create an empty network object */
  ierr = DMNetworkCreate(PETSC_COMM_WORLD,&networkdm);CHKERRQ(ierr);
  /* Register the components in the network */
  ierr = DMNetworkRegisterComponent(networkdm,"branchstruct",sizeof(struct _p_EDGEDATA),&componentkey[0]);CHKERRQ(ierr);
  ierr = DMNetworkRegisterComponent(networkdm,"busstruct",sizeof(struct _p_VERTEXDATA),&componentkey[1]);CHKERRQ(ierr);
  ierr = DMNetworkRegisterComponent(networkdm,"genstruct",sizeof(struct _p_GEN),&componentkey[2]);CHKERRQ(ierr);
  ierr = DMNetworkRegisterComponent(networkdm,"loadstruct",sizeof(struct _p_LOAD),&componentkey[3]);CHKERRQ(ierr);

  ierr = PetscLogStageRegister("Read Data",&stage1);CHKERRQ(ierr);
  PetscLogStagePush(stage1);
  /* READ THE DATA */
  if (!rank) {
    /*    READ DATA */
    /* Only rank 0 reads the data */
    ierr = PetscOptionsGetString(NULL,NULL,"-pfdata",pfdata_file,PETSC_MAX_PATH_LEN-1,NULL);CHKERRQ(ierr);
    ierr = PetscNew(&pfdata);CHKERRQ(ierr);
    ierr = PFReadMatPowerData(pfdata,pfdata_file);CHKERRQ(ierr);
    User.Sbase = pfdata->sbase;

    numEdges = pfdata->nbranch;
    numVertices = pfdata->nbus;

    ierr = PetscMalloc(2*numEdges*sizeof(int),&edges);CHKERRQ(ierr);
    ierr = GetListofEdges(pfdata->nbranch,pfdata->branch,edges);CHKERRQ(ierr);
  }
  PetscLogStagePop();
  ierr = MPI_Barrier(PETSC_COMM_WORLD);CHKERRQ(ierr);
  ierr = PetscLogStageRegister("Create network",&stage2);CHKERRQ(ierr);
  PetscLogStagePush(stage2);
  /* Set number of nodes/edges */
  ierr = DMNetworkSetSizes(networkdm,numVertices,numEdges,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
  /* Add edge connectivity */
  ierr = DMNetworkSetEdgeList(networkdm,edges);CHKERRQ(ierr);
  /* Set up the network layout */
  ierr = DMNetworkLayoutSetUp(networkdm);CHKERRQ(ierr);

  if (!rank) {
    ierr = PetscFree(edges);CHKERRQ(ierr);
  }
  /* Add network components */
  
  genj=0; loadj=0;
  ierr = DMNetworkGetEdgeRange(networkdm,&eStart,&eEnd);CHKERRQ(ierr);
  for (i = eStart; i < eEnd; i++) {
    ierr = DMNetworkAddComponent(networkdm,i,componentkey[0],&pfdata->branch[i-eStart]);CHKERRQ(ierr);
  }
  ierr = DMNetworkGetVertexRange(networkdm,&vStart,&vEnd);CHKERRQ(ierr);
  for (i = vStart; i < vEnd; i++) {
    ierr = DMNetworkAddComponent(networkdm,i,componentkey[1],&pfdata->bus[i-vStart]);CHKERRQ(ierr);
    if (pfdata->bus[i-vStart].ngen) {
      for (j = 0; j < pfdata->bus[i-vStart].ngen; j++) {
	ierr = DMNetworkAddComponent(networkdm,i,componentkey[2],&pfdata->gen[genj++]);CHKERRQ(ierr);
      }
    }
    if (pfdata->bus[i-vStart].nload) {
      for (j=0; j < pfdata->bus[i-vStart].nload; j++) {
	ierr = DMNetworkAddComponent(networkdm,i,componentkey[3],&pfdata->load[loadj++]);CHKERRQ(ierr);
      }
    }
    /* Add number of variables */
    ierr = DMNetworkAddNumVariables(networkdm,i,2);CHKERRQ(ierr);
  }
  /* Set up DM for use */
  ierr = DMSetUp(networkdm);CHKERRQ(ierr);

  if (!rank) {
    ierr = PetscFree(pfdata->bus);CHKERRQ(ierr);
    ierr = PetscFree(pfdata->gen);CHKERRQ(ierr);
    ierr = PetscFree(pfdata->branch);CHKERRQ(ierr);
    ierr = PetscFree(pfdata->load);CHKERRQ(ierr);
    ierr = PetscFree(pfdata);CHKERRQ(ierr);
  }


  ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
  if (size > 1) {
    DM distnetworkdm;
    /* Network partitioning and distribution of data */
    ierr = DMNetworkDistribute(networkdm,0,&distnetworkdm);CHKERRQ(ierr);
    ierr = DMDestroy(&networkdm);CHKERRQ(ierr);
    networkdm = distnetworkdm;
  }

  PetscLogStagePop();
  ierr = DMNetworkGetEdgeRange(networkdm,&eStart,&eEnd);CHKERRQ(ierr);
  ierr = DMNetworkGetVertexRange(networkdm,&vStart,&vEnd);CHKERRQ(ierr);
  
#if 0
  PetscInt numComponents;
  EDGEDATA edge;
  PetscInt offset,key,kk;
  DMNetworkComponentGenericDataType *arr;
  VERTEXDATA     bus;
  GEN            gen;
  LOAD           load;
   
  for (i = eStart; i < eEnd; i++) {
    ierr = DMNetworkGetComponentDataArray(networkdm,&arr);CHKERRQ(ierr);
    ierr = DMNetworkGetComponentTypeOffset(networkdm,i,0,&key,&offset);CHKERRQ(ierr);
    edge = (EDGEDATA)(arr+offset);
    ierr = DMNetworkGetNumComponents(networkdm,i,&numComponents);CHKERRQ(ierr);
    ierr = PetscPrintf(PETSC_COMM_SELF,"Rank %d ncomps = %d Line %d ---- %d\n",rank,numComponents,edge->internal_i,edge->internal_j);CHKERRQ(ierr);
  }    

  for (i = vStart; i < vEnd; i++) {
    ierr = DMNetworkGetComponentDataArray(networkdm,&arr);CHKERRQ(ierr);
    ierr = DMNetworkGetNumComponents(networkdm,i,&numComponents);CHKERRQ(ierr);
    for (kk=0; kk < numComponents; kk++) {
      ierr = DMNetworkGetComponentTypeOffset(networkdm,i,kk,&key,&offset);CHKERRQ(ierr);
      if (key == 1) {
	bus = (VERTEXDATA)(arr+offset);
	ierr = PetscPrintf(PETSC_COMM_SELF,"Rank %d ncomps = %d Bus %d\n",rank,numComponents,bus->internal_i);CHKERRQ(ierr);
      } else if (key == 2) {
	gen = (GEN)(arr+offset);
	ierr = PetscPrintf(PETSC_COMM_SELF,"Rank %d Gen pg = %f qg = %f\n",rank,gen->pg,gen->qg);CHKERRQ(ierr);
      } else if (key == 3) {
	load = (LOAD)(arr+offset);
	ierr = PetscPrintf(PETSC_COMM_SELF,"Rank %d Load pl = %f ql = %f\n",rank,load->pl,load->ql);CHKERRQ(ierr);
      }
    }
  }  
#endif  
  /* Broadcast Sbase to all processors */
  ierr = MPI_Bcast(&User.Sbase,1,MPIU_SCALAR,0,PETSC_COMM_WORLD);CHKERRQ(ierr);

  ierr = DMCreateGlobalVector(networkdm,&X);CHKERRQ(ierr);
  ierr = VecDuplicate(X,&F);CHKERRQ(ierr);

  ierr = DMCreateMatrix(networkdm,&J);CHKERRQ(ierr);
  ierr = MatSetOption(J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);CHKERRQ(ierr);

  ierr = SetInitialValues(networkdm,X,&User);CHKERRQ(ierr);

  /* HOOK UP SOLVER */
  ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr);
  ierr = SNESSetDM(snes,networkdm);CHKERRQ(ierr);
  ierr = SNESSetFunction(snes,F,FormFunction,&User);CHKERRQ(ierr);
  ierr = SNESSetJacobian(snes,J,J,FormJacobian,&User);CHKERRQ(ierr);
  ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);

  ierr = SNESSolve(snes,NULL,X);CHKERRQ(ierr);

  ierr = VecDestroy(&X);CHKERRQ(ierr);
  ierr = VecDestroy(&F);CHKERRQ(ierr);
  ierr = MatDestroy(&J);CHKERRQ(ierr);

  ierr = SNESDestroy(&snes);CHKERRQ(ierr);
  ierr = DMDestroy(&networkdm);CHKERRQ(ierr);

  PetscFinalize();
  return 0;
}