diff --git a/modules/find/FindPETSC.cmake b/modules/find/FindPETSC.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..cd1e3b93f8900588e3175485a15416ee91f29b67
--- /dev/null
+++ b/modules/find/FindPETSC.cmake
@@ -0,0 +1,210 @@
+# - Try to find PETSc
+# Once done this will define
+#
+#  PETSC_FOUND             - system has PETSc
+#  PETSC_INCLUDE_DIRS      - include directories for PETSc
+#  PETSC_LIBRARY_DIRS      - library directories for PETSc
+#  PETSC_LIBRARIES         - libraries for PETSc
+#  PETSC_STATIC_LIBRARIES  - libraries for PETSc (static linking, undefined if not required)
+#  PETSC_VERSION           - version for PETSc
+#  PETSC_VERSION_MAJOR     - First number in PETSC_VERSION
+#  PETSC_VERSION_MINOR     - Second number in PETSC_VERSION
+#  PETSC_VERSION_SUBMINOR  - Third number in PETSC_VERSION
+#  PETSC_INT_SIZE          - sizeof(PetscInt)
+#
+#=============================================================================
+# Copyright (C) 2010-2016 Garth N. Wells, Anders Logg and Johannes Ring
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+# Outline:
+# 1. Get flags from PETSc-generated pkg-config file
+# 2. Test compile and run program using shared library linking
+# 3. If shared library linking fails, test with static library linking
+
+# Load pkg-config module (provided by CMake)
+find_package(PkgConfig REQUIRED)
+
+# Find PETSc pkg-config file. Note: craypetsc_real is on Cray systems
+set(ENV{PKG_CONFIG_PATH} "$ENV{CRAY_PETSC_PREFIX_DIR}/lib/pkgconfig:$ENV{PETSC_DIR}/$ENV{PETSC_ARCH}/lib/pkgconfig:$ENV{PETSC_DIR}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
+pkg_search_module(PETSC craypetsc_real PETSc)
+
+# Extract major, minor, etc from version string
+if (PETSC_VERSION)
+  string(REPLACE "." ";" VERSION_LIST ${PETSC_VERSION})
+  list(GET VERSION_LIST 0 PETSC_VERSION_MAJOR)
+  list(GET VERSION_LIST 1 PETSC_VERSION_MINOR)
+  list(GET VERSION_LIST 2 PETSC_VERSION_SUBMINOR)
+endif()
+
+# Configure PETSc IMPORT (this involves creating an 'imported' target
+# and attaching 'properties')
+if (PETSC_FOUND AND NOT TARGET PETSC::petsc)
+  add_library(PETSC::petsc INTERFACE IMPORTED)
+
+  # Add include paths
+  set_property(TARGET PETSC::petsc PROPERTY
+    INTERFACE_INCLUDE_DIRECTORIES ${PETSC_INCLUDE_DIRS})
+
+  # Add libraries
+  unset(_libs)
+  foreach (lib ${PETSC_LIBRARIES})
+    find_library(LIB_${lib} NAMES ${lib} PATHS ${PETSC_LIBRARY_DIRS} NO_DEFAULT_PATH)
+    list(APPEND _libs ${LIB_${lib}})
+  endforeach()
+  set_property(TARGET PETSC::petsc PROPERTY INTERFACE_LINK_LIBRARIES "${_libs}")
+endif()
+
+# Configure PETSc 'static' IMPORT (this involves creating an
+# 'imported' target and attaching 'properties')
+if (PETSC_FOUND AND NOT TARGET PETSC::petsc_static)
+  add_library(PETSC::petsc_static INTERFACE IMPORTED)
+
+  # Add libraries (static)
+  unset(_libs)
+  foreach (lib ${PETSC_STATIC_LIBRARIES})
+    find_library(LIB_${lib} ${lib} HINTS ${PETSC_STATIC_LIBRARY_DIRS})
+    list(APPEND _libs ${LIB_${lib}})
+  endforeach()
+  set_property(TARGET PETSC::petsc_static PROPERTY INTERFACE_LINK_LIBRARIES "${_libs}")
+endif()
+
+# Attempt to build and run PETSc test program
+if (DOLFIN_SKIP_BUILD_TESTS)
+
+  # Assume PETSc works
+  set(PETSC_TEST_RUNS TRUE)
+
+elseif (PETSC_FOUND)
+
+  # Create PETSc test program
+  set(PETSC_TEST_LIB_CPP
+    "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/petsc_test_lib.cpp")
+  file(WRITE ${PETSC_TEST_LIB_CPP} "
+#include \"petscts.h\"
+#include \"petsc.h\"
+int main()
+{
+  PetscErrorCode ierr;
+  TS ts;
+  int argc = 0;
+  char** argv = NULL;
+  ierr = PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
+  ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr);
+  ierr = TSSetFromOptions(ts);CHKERRQ(ierr);
+  ierr = TSDestroy(&ts);CHKERRQ(ierr);
+  ierr = PetscFinalize();CHKERRQ(ierr);
+  return 0;
+}
+")
+
+  # Add MPI variables if MPI has been found
+  if (MPI_C_FOUND)
+    set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MPI_C_INCLUDE_PATH})
+    set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${MPI_C_LIBRARIES})
+    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${MPI_C_COMPILE_FLAGS}")
+  endif()
+
+  # Try to run test program (shared linking)
+  try_run(
+    PETSC_TEST_LIB_EXITCODE
+    PETSC_TEST_LIB_COMPILED
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${PETSC_TEST_LIB_CPP}
+    CMAKE_FLAGS
+    "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}"
+    "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}"
+    LINK_LIBRARIES PETSC::petsc
+    COMPILE_OUTPUT_VARIABLE PETSC_TEST_LIB_COMPILE_OUTPUT
+    RUN_OUTPUT_VARIABLE PETSC_TEST_LIB_OUTPUT)
+
+  # Check program output
+  if (PETSC_TEST_LIB_COMPILED AND PETSC_TEST_LIB_EXITCODE EQUAL 0)
+
+    message(STATUS "Test PETSC_TEST_RUNS with shared library linking - Success")
+    set(PETSC_TEST_RUNS TRUE)
+
+    # Static libraries not required, so unset
+    set_property(TARGET PETSC::petsc_static PROPERTY INTERFACE_LINK_LIBRARIES)
+
+  else()
+
+    message(STATUS "Test PETSC_TEST_RUNS with shared library linking - Failed")
+
+    # Add MPI variables if MPI has been found
+    if (MPI_C_FOUND)
+      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MPI_C_INCLUDE_PATH})
+      set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${MPI_C_LIBRARIES})
+      set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${MPI_C_COMPILE_FLAGS}")
+    endif()
+
+    # Try to run test program (static linking)
+    try_run(
+      PETSC_TEST_LIB_EXITCODE
+      PETSC_TEST_LIB_COMPILED
+      ${CMAKE_CURRENT_BINARY_DIR}
+      ${PETSC_TEST_LIB_CPP}
+      CMAKE_FLAGS
+      "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}"
+      "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}"
+      LINK_LIBRARIES PETSC::petsc PETSC::petsc_static
+      COMPILE_OUTPUT_VARIABLE PETSC_TEST_LIB_COMPILE_OUTPUT
+      RUN_OUTPUT_VARIABLE PETSC_TEST_LIB_OUTPUT)
+
+    if (PETSC_TEST_LIB_COMPILED AND PETSC_TEST_LIB_EXITCODE EQUAL 0)
+      message(STATUS "Test PETSC_TEST_RUNS static linking - Success")
+      set(PETSC_TEST_RUNS TRUE)
+    else()
+      message(STATUS "Test PETSC_TEST_RUNS static linking - Failed")
+      set(PETSC_TEST_RUNS FALSE)
+    endif()
+
+  endif()
+endif()
+
+# Check sizeof(PetscInt)
+if (PETSC_INCLUDE_DIRS)
+  include(CheckTypeSize)
+  set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${PETSC_INCLUDE_DIRS})
+  set(CMAKE_EXTRA_INCLUDE_FILES petscsys.h)
+  check_type_size("PetscInt" PETSC_INT_SIZE)
+
+  unset(CMAKE_EXTRA_INCLUDE_FILES)
+  unset(CMAKE_REQUIRED_INCLUDES)
+endif()
+
+# Standard package handling
+include(FindPackageHandleStandardArgs)
+if (PETSC_FOUND)
+  find_package_handle_standard_args(PETSc
+    REQUIRED_VARS PETSC_FOUND PETSC_TEST_RUNS VERSION_VAR PETSC_VERSION
+    FAIL_MESSAGE "PETSc could not be configured.")
+else()
+  find_package_handle_standard_args(PETSc
+    REQUIRED_VARS PETSC_FOUND
+    FAIL_MESSAGE "PETSc could not be found. Be sure to set PETSC_DIR.")
+endif()