← Back to team overview

fenics team mailing list archive

Re: [Branch ~fenics-core/fenics-doc/main] Rev 14: Added script to check code blocks in the demo directories and fixed some inconsistencies that the...

 

Cool!

--
Anders


On Sat, May 01, 2010 at 03:27:19PM -0000, noreply@xxxxxxxxxxxxx wrote:
> ------------------------------------------------------------
> revno: 14
> committer: Kristian B. Ølgaard <k.b.oelgaard@xxxxxxxxx>
> branch nick: fenics-doc
> timestamp: Sat 2010-05-01 17:25:57 +0200
> message:
>   Added script to check code blocks in the demo directories and fixed some inconsistencies that the script found.
> added:
>   source/demos/python/pde/poisson/demo.py
>   verify_code_snippets.py
> modified:
>   source/demos/cpp/pde/cahn-hilliard/cahn-hilliard.rst
>   source/demos/cpp/pde/poisson/poisson.rst
>   source/demos/python/pde/cahn-hilliard/cahn-hilliard.rst
>   source/demos/python/pde/poisson/poisson.rst
>
>

> === modified file 'source/demos/cpp/pde/cahn-hilliard/cahn-hilliard.rst'
> --- source/demos/cpp/pde/cahn-hilliard/cahn-hilliard.rst	2010-04-29 11:35:24 +0000
> +++ source/demos/cpp/pde/cahn-hilliard/cahn-hilliard.rst	2010-05-01 15:25:57 +0000
> @@ -56,47 +56,51 @@
>
>  .. code-block:: c++
>
> -   #include <dolfin.h>
> -   #include "Poisson.h"
> +    #include <dolfin.h>
> +    #include "CahnHilliard2D.h"
> +    #include "CahnHilliard3D.h"
>
> -   using namespace dolfin;
> +    using namespace dolfin;
>
>  Some more C++
>
>  .. code-block:: c++
>
> -  // Source term (right-hand side)
> -  class Source : public Expression
> -  {
> -    void eval(Array<double>& values, const Array<double>& x) const
> -    {
> -      double dx = x[0] - 0.5;
> -      double dy = x[1] - 0.5;
> -      values[0] = 10*exp(-(dx*dx + dy*dy) / 0.02);
> -    }
> -  };
> -
> -  // Boundary flux (Neumann boundary condition)
> -  class Flux : public Expression
> -  {
> -    void eval(Array<double>& values, const Array<double>& x) const
> -    {
> -      values[0] = -sin(5*x[0]);
> -    }
> -  };
> +    // Initial conditions
> +    class InitialConditions : public Expression
> +    {
> +    public:
> +
> +      InitialConditions(const Mesh& mesh) : Expression(mesh.topology().dim())
> +      {
> +        dolfin::seed(2);
> +      }
> +
> +      void eval(Array<double>& values, const Data& data) const
> +      {
> +        values[0]= 0.0;
> +        values[1]= 0.63 + 0.02*(0.5 - dolfin::rand());
> +      }
> +
> +    };
>
>  Yet more C++
>
>  .. code-block:: c++
>
> -  // Sub domain for Dirichlet boundary condition
> -  class DirichletBoundary : public SubDomain
> +  // Solve
> +  while (t < T)
>    {
> -    bool inside(const Array<double>& x, bool on_boundary) const
> -    {
> -      return x[0] < DOLFIN_EPS or x[0] > 1.0 - DOLFIN_EPS;
> -    }
> -  };
> +    // Update for next time step
> +    t += dt;
> +    u0.vector() = u.vector();
> +
> +    // Solve
> +    newton_solver.solve(cahn_hilliard, u.vector());
> +
> +    // Save function to file
> +    file << u[1];
> +  }
>
>  All this should be in the same :download:`main.cpp` file.
>
>
> === modified file 'source/demos/cpp/pde/poisson/poisson.rst'
> --- source/demos/cpp/pde/poisson/poisson.rst	2010-04-29 11:35:24 +0000
> +++ source/demos/cpp/pde/poisson/poisson.rst	2010-05-01 15:25:57 +0000
> @@ -24,7 +24,7 @@
>     g = Coefficient(element)
>
>     a = inner(grad(v), grad(u))*dx
> -   L = v*f*dx + v*h*ds
> +   L = v*f*dx + v*g*ds
>
>
>  Some C++
>
> === modified file 'source/demos/python/pde/cahn-hilliard/cahn-hilliard.rst'
> --- source/demos/python/pde/cahn-hilliard/cahn-hilliard.rst	2010-04-29 11:35:24 +0000
> +++ source/demos/python/pde/cahn-hilliard/cahn-hilliard.rst	2010-05-01 15:25:57 +0000
> @@ -10,3 +10,6 @@
>  .. include:: ../../../common/pde/cahn-hilliard/cahn-hilliard.txt
>
>  This text is Python specific
> +
> +
> +
>
> === added file 'source/demos/python/pde/poisson/demo.py'
> --- source/demos/python/pde/poisson/demo.py	1970-01-01 00:00:00 +0000
> +++ source/demos/python/pde/poisson/demo.py	2010-05-01 15:25:57 +0000
> @@ -0,0 +1,51 @@
> +"""This demo program solves Poisson's equation
> +
> +    - div grad u(x, y) = f(x, y)
> +
> +on the unit square with source f given by
> +
> +    f(x, y) = 10*exp(-((x - 0.5)^2 + (y - 0.5)^2) / 0.02)
> +
> +and boundary conditions given by
> +
> +    u(x, y) = 0        for x = 0 or x = 1
> +du/dn(x, y) = -sin(5*x) for y = 0 or y = 1
> +"""
> +
> +__author__ = "Anders Logg (logg@xxxxxxxxx)"
> +__date__ = "2007-08-16 -- 2010-03-05"
> +__copyright__ = "Copyright (C) 2007-2009 Anders Logg"
> +__license__  = "GNU LGPL Version 2.1"
> +
> +from dolfin import *
> +
> +# Create mesh and define function space
> +mesh = UnitSquare(32, 32)
> +V = FunctionSpace(mesh, "CG", 1)
> +
> +# Define Dirichlet boundary (x = 0 or x = 1)
> +def boundary(x):
> +    return x[0] < DOLFIN_EPS or x[0] > 1.0 - DOLFIN_EPS
> +
> +# Define boundary condition
> +u0 = Constant(0.0)
> +bc = DirichletBC(V, u0, boundary)
> +
> +# Define variational problem
> +v = TestFunction(V)
> +u = TrialFunction(V)
> +f = Expression("10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)")
> +g = Expression("-sin(5*x[0])")
> +a = inner(grad(v), grad(u))*dx
> +L = v*f*dx + v*g*ds
> +
> +# Compute solution
> +problem = VariationalProblem(a, L, bc)
> +u = problem.solve()
> +
> +# Save solution in VTK format
> +file = File("poisson.pvd")
> +file << u
> +
> +# Plot solution
> +plot(u, interactive=True)
>
> === modified file 'source/demos/python/pde/poisson/poisson.rst'
> --- source/demos/python/pde/poisson/poisson.rst	2010-04-29 11:35:24 +0000
> +++ source/demos/python/pde/poisson/poisson.rst	2010-05-01 15:25:57 +0000
> @@ -9,4 +9,16 @@
>
>  .. include:: ../../../common/pde/poisson/poisson.txt
>
> -This text is Python specific
> +This text is Python specific.
> +Here is a code snippet from the Poisson :download:`demo.py`:
> +
> +.. code-block:: python
> +
> +    # Define variational problem
> +    v = TestFunction(V)
> +    u = TrialFunction(V)
> +    f = Expression("10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)")
> +    g = Expression("-sin(5*x[0])")
> +    a = inner(grad(v), grad(u))*dx
> +    L = v*f*dx + v*g*ds
> +
>
> === added file 'verify_code_snippets.py'
> --- verify_code_snippets.py	1970-01-01 00:00:00 +0000
> +++ verify_code_snippets.py	2010-05-01 15:25:57 +0000
> @@ -0,0 +1,138 @@
> +#!usr/bin/env python
> +
> +"""This utility script will find all *.rst files in the source/demo
> +directory and check that any code snippets highlighted by the .. code-block::
> +directive is legal in the sense that it is present in at least one of the
> +source files (.ufl, .py, .cpp) that is associated with the demo."""
> +
> +from os import chdir, path, getcwd, curdir, pardir, listdir
> +from sys import stderr
> +
> +# We currently only verifies demo code.
> +chdir(path.join("source","demos"))
> +
> +# Save current location (needed?).
> +demo_dir = getcwd()
> +
> +# We have C++ and Python versions of the demos.
> +directories = ["cpp", "python"]
> +
> +# Dictionary of code blocks that has to be checked for each subdirectory
> +# including information about file types of the source.
> +block_source =  {"cpp":     {"c++": ".cpp", "python": ".ufl"},
> +                 "python":  {"python": ".py"}
> +                }
> +
> +def verify_blocks(rst_file, source_files, source_dict):
> +    """Check that any code blocks in the rst file is present in at least one of
> +    the source files."""
> +
> +    for block_type, source_type in source_dict.items():
> +        # Extract code blocks from rst file.
> +        blocks = get_blocks(rst_file, block_type)
> +        for block in blocks:
> +            # Check if block is in the list of files of correct type.
> +            block_in_source(block, [sf for sf in source_files\
> +                                    if path.splitext(sf)[-1] == source_type])
> +
> +def get_blocks(rst_file, block_type):
> +    "Extract any code blocks of given type from the rst file."
> +
> +    blocks = []
> +
> +    # Open file and read lines.
> +    f = open(rst_file, "r")
> +    lines = f.read().split("\n")
> +
> +    code = False
> +    block = []
> +    for l in lines:
> +        # Get start of code block.
> +        if "code-block::" in l and block_type in l:
> +            code = True
> +            block = []
> +            continue
> +        # The first line which is not an indented line terminates the code
> +        # block.
> +        if code and l and l[0] != " ":
> +            code = False
> +            # Join the block that we have and add to list of blocks.
> +            # Remove any whitespace.
> +            blocks.append(remove_whitespace("\n".join(block)))
> +        # If code is still True, then the line is part of the code block.
> +        if code:
> +            block.append(l)
> +
> +    # Add block of code if found at the end of the rst file.
> +    if code:
> +        blocks.append(remove_whitespace("\n".join(block)))
> +
> +    # Close file and return blocks.
> +    f.close()
> +    return blocks
> +
> +def remove_whitespace(code):
> +    "Remove blank lines and whitespace in front of lines."
> +    return "\n".join([" ".join(l.split())\
> +                      for l in code.split("\n") if l != ""])
> +
> +def block_in_source(block, source_files):
> +    """Check that the code block is present in at least one of
> +    the source files."""
> +
> +    present = False
> +    code = ""
> +    for sf in source_files:
> +        f = open(sf, "r")
> +        # Read code and remove whitespace before comparing block and code.
> +        code = remove_whitespace(f.read())
> +
> +        if block in code:
> +            present = True
> +        f.close()
> +
> +        # If code is present, look no further.
> +        if present:
> +            return
> +
> +    # Just crash the test, no need to proceed. We MUST fix the
> +    if not present:
> +        if not source_files:
> +            raise RuntimeError("No source file!")
> +
> +        print "\nError:"
> +        print "\ncode block:\n", block
> +        print "\ncode:\n", code
> +        print "source_files:", source_files
> +        print "in directory: ", getcwd()
> +        raise RuntimeError("Illegal code block.")
> +
> +if __name__ == "__main__":
> +
> +    print "\nTesting that all code snippets are valid.\n"
> +    # Loop directories/categories/demos
> +    for directory in directories:
> +        chdir(directory)
> +        # Get all demo categories
> +        categories = [d for d in listdir(curdir) if path.isdir(d)]
> +        for category in categories:
> +            chdir(category)
> +            demos = [d for d in listdir(curdir) if path.isdir(d)]
> +            for demo in demos:
> +                chdir(demo)
> +                stderr.write(" "*2 + path.join(directory, category, demo))
> +                # Get files in demo directory and sort in rst and source files.
> +                files = listdir(curdir)
> +                rst_files = [f for f in files if path.splitext(f)[-1] == ".rst"]
> +                source_files = [f for f in files if path.splitext(f)[-1] in\
> +                                  (".py", ".ufl", ".cpp")]
> +                # Loop files, check if code blocks are present in source files.
> +                for rst_file in rst_files:
> +                    verify_blocks(rst_file, source_files, block_source[directory])
> +                stderr.write(", " + "OK.\n")
> +                chdir(pardir)
> +            chdir(pardir)
> +        chdir(pardir)
> +
> +    print "\nOK.\n"
> +
>

Attachment: signature.asc
Description: Digital signature