Index: include/numerics/petsc_matrix.h
===================================================================
--- include/numerics/petsc_matrix.h	(revision 4241)
+++ include/numerics/petsc_matrix.h	(working copy)
@@ -666,26 +666,6 @@
 }
 
 
-
-
-
-template <typename T>
-inline
-void PetscMatrix<T>::print_personal(std::ostream& os) const
-{
-  libmesh_assert (this->initialized());
-
-#ifndef NDEBUG
-  if (os != std::cout)
-    libMesh::err << "Warning! PETSc can only print to std::cout!" << std::endl;
-#endif
-  
-  int ierr=0;
-
-  ierr = MatView(_mat, PETSC_VIEWER_STDOUT_SELF);
-         CHKERRABORT(libMesh::COMM_WORLD,ierr);
-}
-
 } // namespace libMesh
 
 #endif // #ifdef LIBMESH_HAVE_PETSC
Index: src/numerics/petsc_matrix.C
===================================================================
--- src/numerics/petsc_matrix.C	(revision 4241)
+++ src/numerics/petsc_matrix.C	(working copy)
@@ -19,6 +19,8 @@
 
 
 // C++ includes
+// #include <unistd.h> // mkstemp
+
 #include "libmesh_config.h"
 
 #ifdef LIBMESH_HAVE_PETSC
@@ -329,7 +331,91 @@
 
 
 
+
 template <typename T>
+void PetscMatrix<T>::print_personal(std::ostream& os) const
+{
+  libmesh_assert (this->initialized());
+
+  // Routine must be called in parallel on parallel matrices
+  // and serial on serial matrices.
+  semiparallel_only();
+  
+// #ifndef NDEBUG
+//   if (os != std::cout)
+//     libMesh::err << "Warning! PETSc can only print to std::cout!" << std::endl;
+// #endif
+
+  // Matrix must be in an assembled state to be printed
+  this->close();
+  
+  int ierr=0;
+
+  // Print to screen if ostream is stdout
+  if (os == std::cout)
+    {
+      ierr = MatView(_mat, PETSC_VIEWER_STDOUT_SELF);
+      CHKERRABORT(libMesh::COMM_WORLD,ierr);
+    }
+  
+  // Otherwise, print to the requested file, in a roundabout way...
+  else 
+    {
+      // This is the "right" way to create a unique filename:
+      // mkstemp will replace X's with unique number.  But I'm not
+      // sure what this will do in parallel, so I'm not gonna do it...
+      //       char temp_filename[] = "temp_petsc_matrix.XXXXXX"; 
+      //       int fd = mkstemp(temp_filename);
+      
+      //       // Check to see that mkstemp did not fail.
+      //       if (fd == -1)
+      // 	libmesh_error();
+      
+      // Temporary filename, not guaranteed to be unique, but probably will be!
+      const char* temp_filename = "libmesh_temp_petsc_matrix.081702"; 
+
+      // PetscViewer object for passing to MatView
+      PetscViewer petsc_viewer;
+
+      // This PETSc function only takes a string and handles the opening/closing
+      // of the file internally.  Since print_personal() takes a reference to
+      // an ostream, we have to do an extra step...  print_personal() should probably
+      // have a version that takes a string to get rid of this problem.
+      ierr = PetscViewerASCIIOpen( libMesh::COMM_WORLD,
+				   temp_filename, 
+				   &petsc_viewer);
+      CHKERRABORT(libMesh::COMM_WORLD,ierr);
+
+      // Probably don't need to set the format if it's default... 
+      //      ierr = PetscViewerSetFormat (petsc_viewer,
+      //				   PETSC_VIEWER_DEFAULT);
+      //      CHKERRABORT(libMesh::COMM_WORLD,ierr);
+
+      // Finally print the matrix using the viewer
+      ierr = MatView (_mat, petsc_viewer);
+      CHKERRABORT(libMesh::COMM_WORLD,ierr);
+
+      if (libMesh::processor_id() == 0)
+	{
+	  // Now the inefficient bit: open temp_filename as an ostream and copy the contents
+	  // into the user's desired ostream.  We can't just do a direct file copy, we don't even have the filename!
+	  std::ifstream input_stream(temp_filename);
+	  os << input_stream.rdbuf();  // The "most elegant" way to copy one stream into another.
+	  // os.close(); // close not defined in ostream
+
+	  // Now remove the temporary file
+	  input_stream.close();
+	  std::remove(temp_filename);
+	}
+    }
+}
+
+  
+
+
+
+
+template <typename T>
 void PetscMatrix<T>::add_matrix(const DenseMatrix<T>& dm,
 				const std::vector<unsigned int>& rows,
 				const std::vector<unsigned int>& cols)
