GSoC 2013 Application Prasoon Shukla: Vector Calculus Module

Prasoon Shukla edited this page May 2, 2013 · 13 revisions
Clone this wiki locally

Note: Proposal submitted to melange is here.

About me

Hi. My name is Prasoon Shukla, a second year undergrad at IIT Roorkee, India. I am pursuing a degree in Applied Mathematics.

Username/Contact information:

Email: prasoon92.iitr@gmail.com

Google Code: prasoon92.iitr@gmail.com

Github: prasoon2211

IRC: prasoon2211 (occasionally available)

Programming and Mathematical Background

I began coding during my freshman year at college. My first real work was the development of an app written in Python/Django for my college's intranet portal. Since then, I have done a lot of work in Django including two more major applications for the intranet portal. I have also done quite a bit of work in PHP as well.

I was introduced to Python about a year back. In the year I have used Python, I have really came to love it. The feature I really love about Python is its module system. First, it facilitates development a lot, as contributing to code is really easy (as I have found out). Second, as a user, I can import a couple of different things from completely different packages and quickly hack together something entirely different. The key thing here is quickness. I use Python for all of my scripting work precisely for these reasons.

Other that python, I have a semester's worth of C++ programming. I am also familiar with C, JavaScript and PHP. I have also once dabbled with assembly (a very, very little bit) though I can't do anything in it yet.

I use a GNU/Linux distribution as my primary development platform. I keep switching between distros though. For the editor, I primarily use Vim although I have, at times, used Emacs as well. There are many reasons I prefer Vim but mostly what I like about it is that once you are experienced with it, then it doesn't get in your way. Also, there are some really great shortcuts too.

I have been working with git for about a 7 months, primarily for developing apps for my college's intranet portal with about 20 other people. I believe I have a good understanding of the basic git features.

My knowledge of higher mathematics is somewhat limited in scope, yet. I have had a course in calculus and vector calculus, a basic course for ODEs and PDEs, an introductory course in complex analysis, a course in linear algebra and another in numerical analysis and have also studied some other general topics (Fourier, Laplace, Z transforms/ Series solutions of differential equations etc). Among the physics courses that I have taken, there is a course in electrodynamics which is relevant to this proposal.

Contribution to SymPy

I have been contributing to SymPy since February this year. Here is a list of the patches submitted by me:

Merged (sorted by date, earliest first):

  1. My first PR. Made changes to Rational.mod() to check if self was indeed a float. #1709

  2. Tolerance passed to nsimplify with rational=True. #1713

  3. Fix for problems due to IEEE representation of special numbers. #1714. Merged via #1721.

  4. Binomial coefficients not expanded by default. #1726

  5. Passing a dictionary to .n() now works on cos and sin functions. #1736

  6. Closed form solutions of solvable quintics. Had a few unrelated problems with this one. #1746

  7. Problem with addition of order terms solved. #1798

  8. Change factorint to take only integer arguments. #1851

Unmerged:

  1. Expansion of binomials with non-integer powers. The expansion results in a Piecewise object. The PR hasn't been merged because of a problem with Piecewise.as_leading_term(). Temporarily closed this because I was working on this proposal. #1769

The Project


Aim of this project

My project aims at implementing a module for vector calculus in SymPy. The discussions on the Google group page that led to the consolidation of ideas can be found here. Vector calculus is a very fundamental tool for analyzing vector fields and how they change with coordinates. This is a functionality that, in my opinion, any CAS must definitely support. Currently, SymPy has limited support for vector calculus. The mechanics module offers some vector calculus functionality but it is difficult to use it outside of mechanics. The proposed module will allow this functionality to be used with other modules.

Why this project

While going through the ideas page, a lot of the ideas caught my attention. The idea for implementing a vector calculus module though, struck me as something that just needed to be there in SymPy (as I have mentioned before). Also, the implementation was within limits of my mathematical knowledge. So, I looked around a bit and concluded that functionality for vector calculus wasn't available in SymPy, at least not directly.

This then led to discussions on the mailing list and I got know that the mechanics module has implemented vector calculus in some capacity. Nevertheless, further discussion ensued and we concluded that the new module is a good idea for implementing vector calculus functionality outside of mechanics. Also, it was decided that the new module must preserve the basic elements of the functionality in mechanics module.

How I fit

I have had a course in 3 variable vector calculus. That coupled with some help from the SymPy community will be quite sufficient for the mathematics required for the implementation of this project. I have also worked on Python quite a bit and there shouldn't be any difficulties there. Also, I am quite passionate about contributing something significant to SymPy and I see this project as my way of contributing.

Some general information

I will be completely free during this summer. I can devote myself completely to SymPy during that time. I plan to invest from 7 - 9 hours everyday on weekdays and 5 - 7 hours on weekends. This easily covers the 40 hr/week work requirement. I don't plan on taking any vacations.

During April and for the first week of May, I will be quite busy because of quizzes/exams/project submissions etc. I'll be free from 10th of May onward. After this time, I can start working freely on the implementation details of this idea. During this time, I plan start writing some test code to get an idea of the problems I might (read will) face during the course of the actual implementation. Additionally, I will also brush up on the mathematics required for this project. Also, if things go well, I might have a WIP pull request implementing some very basic functionality. I hope that this PR will act as a means to convince the community that this project will be a valuable addition to the SymPy codebase.

After GSoC, I hope to keep on contributing to SymPy as much as I can. Still, I am looking to contribute to some other open source projects too, preferably in C. So, I might not be able to devote too much time but I will definitely stick around. In fact, I hope that in a few years time, when I have more mathematical knowledge, I can become a core committer for SymPy.

Detailed description


The module will provide users to define vector fields and perform operations on them in the most straightforward way. The major components of the module will be the following classes:

  1. CoordSystem
  2. Vector
  3. RefFrame
  4. VectorIntegral
  5. ParamRegion

Each of these classes are explained in detail below.

How to read this?

For every class, I have first explained the parameters that the user will/can provide (the API). Some of the class methods have also been explained, but certainly not all. I have explained only those methods which will be required for the core functionality and the ones which I believe the user will expect. This has been done to keep the proposal to a reasonable length. Also, at places, I have explained the internal working of that class. Often, to understand what one parameter means/does, you might have to read the complete working of the class.

Also, throughout the text, I will try to give examples wherever possible. For the examples, we will be using the following:

>>> c = CoordSystem(name='c', basis_var='e', dim=3, coord_type='rect')  
>>> c_cyl = CoordSystem(name='c_cyl', basis_var='e', dim=3, coord_type='cylindrical')  
>>> c_sph = CoordSystem(name='c_sph', basis_var='e', dim=3, coord_type='spherical')  

These will be used for coordinate system objects. (Please see the description of the CoordSystem class below to understand what these 3 lines of code mean).

CoordSystem


This is a class to represent the coordinate system to be used to represent a point in space. An object of this class will serve to act as a placeholder for the quantities used to represent a coordinate system, the basis elements, for example.

params:

basis_var (string) : a string that will be used to name the basis elements as a prefix. For example, if I give basis_var='x', then the basis symbols generated withing the object will be named x1, x2, x3, .., xn (n is the dimension. See 'dim' argument) for rectangular coordinates (see 'coord_type' argument). This defaults to 'e' for rectangular coordinates of dim >=3. For all other cases, specific default values are defined (such as e_r, e_theta, e_phi for spherical coordinates). These symbols will be generated in the object itself and will be non-commutative.

dim (int) : an integer that defines the dimension of the space to be used. Dimension can be any positive integer for rectangular coordinates. For special coordinates (see 'coord_type'), it can be upto 3.

coord_type (string) : a string that indicates the coordinate system that is used to represent points in space. This can have certain fixed values for every coordinate system that has been implemented. The coordinate systems I have been thinking of implementing are: rectangular, cylindrical polar, spherical polar, Parabolic cylindrical, Paraboloidal coordinates and perharps also Elliptic cylindrical coordinates. This string tells the module what coordinates to use and defines, say, how to take the curl, or say, what is the differential element of integration.

basis (list) : a list of n-tuple representing a basis for the coordinate system. Defaults to standard basis for rectangular coordinates and the standard coordinate dependent basis for other coordinate systems.

For example:

# Quick declaration, defaults to dimension 3, basis as c.e_x,c. e_y and c.e_z  
>>> c = CoordSystem(coord_type='rect')  
# Detailed declaration, spherical polar coordinates  
>>> c = c_sph = CoordSystem(name='c_sph', basis_var='e', dim=3, coord_type='spherical')  

Notes

a) The basis_var is defined by default as per the general convention. So, rectangular 3d basis names would be e_x, e_y, and e_z. Similarly for other coordinates.

b) The coord_type will just store a string that will be used as a check, whenever required, to determine what definitions to use for any vector calculus operations (see Vector class). While initializing data members of the object, this string will be used. For example, the definition of curl will differ in different coordinate systems. Accordingly, a different definition will be stored internally as a part of the CoordSystem object for the curl. Similarly for other vector operations.

c) Whenever the user provides a basis, we check if it's valid (Like checking for linear dependence, zero entries etc)

Also, as suggested on the mailing list, the symbols being generated in the class will be non-commutataive. This will not be done by the user; the user only has to provide the name (s)he wants for the basis. This is done to facilitate vector operations using substitutions on pre-defined dictionaries.

Methods

The CoordSystem object will mainly consist of helper methods methods to support some operations with vectors. Specifically, these methods will support conversions between coordinates systems. For example, we will have a helper method, CoorSystem._convert_to(), which will be used via a Vector to convert the vector from one set of coordinates to another.

Other methods will include (but aren't limited to) functions that will:

  • Evaluate a coordinate dependent basis at a certain point.
    >>> c_sph.eval_at(point=(1, 2, 3))

  • Check if a basis is valid.

    >>> c.set_basis((1, 2, -1), (0, 1, 2), (5, -2, 1))    
    # Change the basis of the coordinate system to another orthonormal basis  
    
    # Here the basis will be checked by default. Or we can just check a basis  
    >>> c.is_valid_basis((1, 2, 1), (2, 4, 2), (3, 2, 6))  
    False  
    # Not linearly independent  
    
  • Output conversion matrices (like the dcm matrix in mechanics).

More Information

Since we are working with component wise vector operations, any vector can be written as: v = c1e1 + c2e2 + .... + cn*en This class will act as a placeholder for (e1, ..., en). These basis elements may be coordinate dependent, in which case the class will hold relationship between the rectangular and any other coordinate system (since for rectangular, the basis remains fixed). Also, since the choice of coordinate systems is limited to 4 or 5 different systems, so, the symbolic relationships between different coordinates will be inbuilt in the class. For conversion between different set of coordinates, we will again use the inbuilt symbolic relationships.

In vector calculus operations, the component wise definitions are different in different coordinates. So, we will store a list/tuple that will contain contain elements such as (h1, h2, .. hn) for performing vector calculus operations on general orthogonal coordinates . Using these elements, we can define vector calculus operations for any coordinate system.

Here, I'd like to mention that the user dependence of this class is really low. The whole class hinges on internally defined relationships between coordinates systems, the definition of various operations, and some other meta-data. As such, to initialize an object of this class, the user input is minimum.

Vector


The Vector class is central to the vector calculus module. This class will hold the component of the vectors.

params:

a) coord_sys (CoordSystem object) : A CoordSystem object that will be used to define how points are specified in space. If not provided, an object will be initialized internally having rectangular coordinates and dimesion three. This variable provides access to all the helper functions defined in the provided object.

b) coords (tuple) : A tuple containing each of the components of the vector (in symbols).

c) vars (tuple) : a tuple containing the symbols to be used to represent each of the different coordinates. These are the symbols that will be used to determine which variables of differentiation/integration. If not provided, we will try to guess the variables (for example, r - theta - phi for spherical coordinates) from the coord_sys parameter. In case we cannot guess correctly, it defaults to (x1, x2, .., xn).

For example: >>> v = Vector(coord_sys=c_cyl, coords=(rho*2, rho*phi, sin(z)), vars=(rho, phi, z))

Methods and operations

The following operations can be performed on a vector once it is defined.

Also note that all methods returning a Vector have a parameter, eval_at, that will take care of the evaluation of the Vector at a point.

  1. Scalar multiplication:
    This multiplies each component of the given vector by a constant. The constant can be a symbol provided via vars in which case, the vector field changes.
    For example:
    >>> v = Vector(coord_sys=c_sph, coords=(2, 3, 4), vars=(r, t, p)) #vars same as used in c_sph  
    >>> c = Symbol('c')   
    >>> (c*v).coords    
    (2*c, 3*c, 4*c)
  1. Vector addition:
    Simple addition of two or more vectors. In case the vectors contain different coord_sys variables, then Vector returned will use the CoordSystem object of the first vector. This then can be converted to a vector in different coordinate system using the method Vector.convert_to() (described later). For the implementation, we are just going to use a component wise addition approach. In case, the two vectors are in different coordinate systems, then one vector will internally be converted to a different coordinate system using the Vector.convert_to method and then added to the other vector. Returns a Vector object.

  2. Dot Product:
    Dot product of two vectors. Returns a scalar SymPy Add object. See the heading Interface > Example for seeing an example.

  3. Cross Product:
    Cross product of two vectors. Returns a Vector. The CoordSystem object is used of the first vector in the cross product. See the heading Interface > Example for seeing an example.

  4. Divergence:
    Vector.div() - Calculate the divergence of a vector field. Returns a scalar field as an Add object.

  5. Curl:
    Vector.curl() - Calculates the curl of a vector field. Returns a Vector object.
    params
    coord_sys (CoordSystem) : A CoordSystem object to express the returned vector in.
    eval_at (list) : a list containing coordinates at which the curl should be evaluated.

Calculating Gradient

A grad() function will be present in the namespace of Vector module.
params
field : The field whose gradient is to be calculated (scalar -> vector, vector->Jacobian matrix). coord_sys (CoordSystem) : The coordinate system in which the Vector will be returned in. Defaults to the CoordSystem of the vector provided.
vars (tuple) : A list of coordinates to use for differentiating the vector.

Other details:
This will support the gradient of undefined function objects. For example:

>>> f = Function('f')(r, t, p) # For r, theta, phi  
>>> g = grad(field=f, coord_sys=c_sph, vars=(r, t, p))  
# representing Derivative with D, D = Derivative  
>>> g.coords  
( D(f(r, t, p), r), D(f(r, t, p), t)/r, D(f(r, t, p), p)/(r*sin(t)) )  

There will also be support for gradient of vector fields in Cartesian coordinates. The Jacobian matrix will be returned in such cases as a SymPy matrix.

Support for the Hessian, as @krastanov mentioned on the mailing list, is not a part of this proposal just yet. There was also talk of implementing dual vectors on the mailing list. The implementation details for this idea aren't clear to me yet. But, I am confident that before 15th of May, I will come up with a good idea at which point I'll discuss it on the mailing list. If some time remains towards the end of the GSoC timeline, then, I'll definitely implement these ideas as well.

Integration

Vector.integrate():

This method will take care of all types of integrals possible with vectors. This calculates the integral of a vector field over any region specified in space. The region is defined parametrically (see ParamRegion for details).

Let F be a vector field. Then we can calculate integrals of F over any region defined parametrically. First, based on the ParamRegion object, we will determine the type of integral. For more details, please see the description of the VectorIntegral class.

params:

region (ParamRegion) : The parametrically defined region to integrate over. (See ParamRegion).

Other methods

Vector.eval_at() : Evaluate a vector at a given point. Returns a Vector.
params
point (list) : A list of coordinates to evaluate the vector field at. coord_sys (CoordSystem) : The coordinate system in which the Vector will be returned in. Defaults to the CoordSystem of the vector provided.

Vector.convert_to() : Convert a vector to another coordinate system. Returns a Vector.
params
coord_sys (CoordSystem) : The coordinate system to convert the vector to.

Vector.diff() : Take the partial derivarive of a vector wrt coordinates or time. Returns a vector. As with all vectors, this can be converted to a vector in a differenet coordinate system.
params var (Symbol) : Symbol to use for differentiation.
coord_sys (CoordSystem) : The coordinate system in which the Vector will be returned in. Defaults to the CoordSystem of the vector provided.

Notes

A point discussed on the mailing list was this: How do you support both constant vectors and vector fields with a common class? Here, the way vectors have been implemented, makes answering this question easy. While vector fields represent vector at a certain point in space, the components of a constant vector remains the same throughout space. It may be the basis that changes from point to point. Thus, while defining the Vector object, the user can just pass constant coordinates to the object. This will work because a constant vector is just a special case of a general vector field, that is, instead of variables, the components are just some constants. Clearly, all the operations defined above will work for a constant component vector as well. To determine whether the given vector is a vector field or not, we just check against the vars parameter provided to the vector. If any of the symbols are present, then it is a vector field. Else it's a constant vector. As discussed on the mailing list, we will have a property, Vector.is_field that will be a part of the user API.

There are infact two kinds of vectors to be thought about at this point. One is obviously vector fields, which depend on point. This kind of vectors cannot be translated from one point to another without chaning them. In the above paragraph, that is the kind that we have talked about. But, there is also another type of vectors, the ones which do not change from translation. Indeed, I think that this was the question which arose on the mailing list. For implementation of this kind of vectors, I plan to have a class which inherits from the Vector class. This class will have some more attributes that will specify completely the free vector.

Another point was about unbounded vectors. Here, we do not pass components to the Vector. This, as was concluded on the mailing list, is not going in the vector module primarily because I cannot see any use of this yet and also because my project idea is based on component wise calculation and unbounded vectors do not allow for that.

More Information

The major user interaction will be through this class. This class serves as a container to hold components of the vector provided by the user, and, provides methods on it. The usual vector calculus operations shouldn't be hard to implement. As we discussed on the list, we will be taking a middle ground between implementing in R3 and Rn. So, for example, the curl operation will only be extend upto 7 dimensions. Similarly, for all things that can be implemented in n dimensions will be implement in n dimesnion. The Vector class will depend upon the CoordSystem class for providing a basis (stationary or otherwise).

RefFrame


params
name (string) : The string for the name of frame.

coord_sys (CoordSystem) : The coordinate system on top of which the reference frame is defined.

time_var (Symbol) : The symbol to use for representing time variable. Defaults to t. Also, note that this symbol must be the same as defined in the Vector object.

The RefFrame class is used implement the concept of a reference frame for vectors. This class will be built as a layer over the CoordSystem class. This is because the essential elements of a reference frame stay the same as those defined in the CoordSystem class. The additional data required to completely express a reference frame are explained below.

Note that throughout the vector module, we will be using the notion of a 'global frame'. So, whenever a user defines a vector 'normally', it is defined with respect to this global frame. All quantities, even the reference frame itself will be defined wrt to this global frame.

Upon initializing a reference frame, the newly created reference frame will be the same as the global frame. A user can use the methods built in the RefFrame class to a) poistion and/or b) orient this frame with respect to the global frame. Obviously, Once the frame is oriented and/or translated, a user can then add r(t), v(t), a(t) and omega(t) ( poition, velocity, acceleration and angular velocity as a function of time) wrt to the global frame. Also, the user can just provide any or all of the three translational parameters (r, v or a). Depending on what parameters are provided, we can generate or check for consistency between all the parameters. Using two variables provided - r_init and v_init, we'd be able to generate r(t) from v(t), and, v(t) from a(t) respectively.

Methods

Since we want to stick to the basics of mechanincs.ReferenceFrame, therefore, we will have similar methods for the most part. The implementation would be different compared to the current ReferenceFrame because we are taking a different, more general approach here.

  1. orient, orientnew : similar as in the mechanics module.

params:

ref_frame (RefFrame) : the reference frame to orient against. Defaults to the global frame.
rot_type (string) : a string to define the type of orientation to perform. Similar to the mechanics module.
amounts (list) : the amounts by which the orientation will occur.
rot_order (string) : string specifying the rotation order.

  1. rot_x, rot_y, rot_z: Methods to rotate the given frame taking x, y and z directions as axes respectively. Unlike the orient, orientnew methods, these three methods are for quick use and orient wrt to the global frame. Does not return anything, changes made in the RefFrame object itself.

params:

amount (value) : how much to rotate by.

Also, these methods can be chained.

Notes

All the time based functionality will be implemented in this class. This decision was taken because there was no other place for incorporating any time dependence in a vector calculus module. We want to abstract vector calculus outside of mechanics and as such the module cannot focus on just a single part.

VectorIntegral


The objects of this class will hold all attributes of an integral over vector fields. This includes the parametric region which includes the limit of parameters (see ParamRegion), the vector field itself and the type.

This object isn't initialized by the user. It is generated by the Vector.integrate() method.

Since VectorIntegral objects aren't initialized by default, I'll first describe how this object may be generated. First, we define a ParamRegion object. Then, operate Vector.integrate() method on a vector field. This will result in a VectorIntegral object. Now, user can interact with this object.

Methods

evalf : Return the numeric value of this integral.

sym_eval : Evaluate symbolically. Return self if cannot evaluate.

convert_gauss : a method to apply gauss theorem to the given integral. Returns a VectorIntegral object with a different ParamRegion object.

convert_stokes : a method to apply stokes theorem to the given integral. Returns a VectorIntegral object with a different ParamRegion object.

Once we call a method on the object to evaluate the integral, it will pass the execution to helper methods wherein, the integral of the vector over the given parametric region will get reduced to simple multiple integrals in the given parameters. These integrals can then be evaluated to return either a symbolic result if possible or a numerical result otherwise.

Also, in reducing the integrals, we will employ all the usual methods used for such a purpose. As an example, we can check whether the curl of a vector field is zero, in which case, the field can be expressed as gradient of some function. Then, the problem of solving the integral reduced to finding the scalar function whose gradient is the given field.

Notes

From my description of this class, it may appear that this class will require relatively less time. The truth is, I suspect the methods of this class may prove the most difficult to code. There is the problem of representing a region of space in patches. Also, the helper methods to simplify the vector integral will also pose somewhat of a challenge to code because we have to make sure that this works for different coordinate systems and n different dimensions. All in all, I think that this class will require some significant amount of time to code properly so that things don't break later on.

ParamRegion


This class represents a region defined parametrically in space. As discussed on the mailing list, we have decided to make just one class that can represent all kinds of regions in space. This object will get passed to the Vector.integrate() method.

Methods

The methods of this class aren't intended to be used by the user for the most part. The methods will serve as helpers during the simplification of integrals.

The methods available to the user will include setter and getter methods (we may add other methods depending on the needs later on).

Interface

The typical workflow would be like this:

  1. Create a CoordSystem object.
  2. Define a RefFrame object (optional).
  3. Create a Vector object by passing the above two objects to it.
  4. Perform operation on the Vector object.

If integration in required,

  1. Create a ParamRegion object.
  2. Pass the above object to the Vector.integrate() method.
  3. This results in a VectorIntegral object. Using methods of this object, the integral can be evaluated symbolically (if possible) or numerically. Also, applications of theorems of vector calculus is also possible.

Example

We will clarify this with a typical vector field example. Let F = x2 e_x + x*y e_y + z2 e_z

Here's how a user will proceed:

>>> from vector import *
>>> from sympy.abc import x, y, z

# x, y, z are variables to use in vector field

>>> c = CoordSystem(name='c', basis_var='e', dim=3, coord_type='rect')
# Now we have a coordinate system in cartesian coordinates to represent our vectors in

>>> c.basis_list
[c.e_x, c.e_y, c.e_z]

>>> components = (x**2, x*y, y**2)

# At this point, F is just an Add
# Now, we define the Vector

>>> v = Vector(coord_sys=c, coords=components, vars=(x, y, z))

# Now, we have a vector defined completely in the global frame, with rectangular coordinate system. The vars argument tells what variables to use for differenting/integrating. Order matters.

# Now, let's do some basic operations

>>> w = 5*v
# Now, w is a new vector created from v. Same coord_sys used.

>>> w.coords
(5*x**2, 5*x*y, 5*y**2)

>>> w.vector
[(5*x**2 * e_x + 5*x*y * e_y + 5*y**2 * e_z), (x, y, z)]

# Now, let us perfom some additions/subtractions

>>> f = w - 4*v
>>> f == v
True

# Now, let us define a spherical polar coordinate system
>>> c_sph = CoordSystem(name='c_sph', basis_var='e', coord_type='sphr')

# Here we don't need to define dimension - spherical coordinates have dim
# as 3 by default.

# Now, let's express the vector field in c_sph
>>> v_sph = v.convert_to(c_sph)

# Now let's check the components of v_sph
>>> v_sph.coords
( r**2 * sin(theta)**2 * cos(phi)**2, r**2 * sin(theta)**2 * sin(phi) * cos(phi), r**2 * sin(theta)**2 * sin(phi)**2  )

>>> v_sph.vector
[( r**2 * sin(theta)**2 * cos(phi)**2 * c_sph.e_r, r**2 * sin(theta)**2 * sin(phi) * cos(phi) * c_sph.e_theta, r**2 * sin(theta)**2 * sin(phi)**2 * c_sph.e_phi  ), (r, theta, phi)]
# Here symbols r, theta and phi are generated automatically within the object.

# Now, we define another vector field. Then we operate the two field with vector operators
>>> componetnts_w = (-x**2, 0, -y**2)
>>> w = Vector(coord_sys=c, coords=components_W, vars=(x, y, z))

# Addition
>>> f = v + w
>>> f.coords
(0, x*y, 0)

# Dot product. Using the same notation as mechanics. Returns Add object
>>> v & w
-x**4 - y**4

# Cross product. Returns a vector 
>>> (v ^ w).coords
(-x*y**3, 0, x**3*y)

# Divergence. Returns Add object
>>> v.div()
3*x

# Curl. Returns a Vector
>>> curl_v = v.curl()
>>> curl_v.vector
[(2*y, 0, y), (x, y, z)]

# Differentiaion. Returns a Vector
>>> (v.diff(x)).coords
(2*x, y, 0)

# Now, let us use the integration methods a bit. These ideas aren't quite as concrete yet.
# I'll just write the example from the mailing list

>>> from sympy.abc import u, v, w
>>> r = ParamRegion(x=5*sin(u)*cos(v), y=5*sin(u)*sin(v), z=5*cos(u), params=(u, v), bounds=[(u, 0, PI), (v, 0, 2*PI) ])

# Now define an integral of v over this parametric surface.
# Using the number of parameters, we can tell what kind of integral this is
>>> I = v.integrate(region=r)
>>> type(I)
<class 'sympy.vector.VectorIntegral'>

>>> I.sym_eval()
< A symbolic result if possible or the object itself. I didn't evaluate this by hand >

>>> I.n()
< A numerical result >

This is just an example of how the new module might be used. As should be obvious, I haven't employed near all the functionality that will be available in this class.

Timeline

Here's the division of my goals with time.

Pre-GSoC period : I'll start with brushing up on the vector calculus that I've had. Also, some ideas need more working on, particularly the integration functionality. During the time I have, I'll research more in this direction (for example, how to represent a region in space with multiple patches). But, I'll be really badly busy till the 10th of May (at which date my exams are ending). I'll get on with the work right after that time.

27 May - 2 June : The timeline provided by Google suggests 20 days of community bonding. That's too long for SymPy since most of the people submitting applications have been around for quite some time. Nevertheless, I'll spend some time on community bonding. I plan to get started with the project in this week (in my experience, starting out with developing something new can sometimes take quite a bit of time). So, this week, in general, would be used to get things going. I'll also begin working with the CoordSystem class.

3 June - 16 June : In these two weeks, I plan to work on both the Vector and CoordSystem class side-by-side. Since most of the functionality in CoordSystem has to be used through Vector, therefore, I'll like to have some basic functionality of the Vector class going. Here are the things I'll most definitely have: In CoordSystem class:

  • Initialization of a coordinate system working completely. This part is actually going to constitute the most time spent this week. Further subparts will include: Writing the constructor. The constructor will, depending upon the 'type' argument, assign values to many things - that include transformation matrices, relation between different coordinate systems (and methods to implement them).
  • Initialize a vector. A vector object at this point will serve only as a container to access methods defined in the CoordSystem object. So, after this week, we will able to convert between coordinate systems.

17 June - 24 June : In this week, I will complete the CoordSystem class. This will include all the methods, including helper methods mentioned above. I will also begin with the documentation of this class. Add some tests for CoordSystem, Vector class.

First pull request.

25 June - 7 July : Finish up work on the Vector class. This includes all the methods described in the description of this class, except the Vector.integrate() method. Also, complete documentation of the Vector class should also be ready by now. All tests added by now.

Second pull request.

By now, the Vector and CoordSystem class will be done and working, complete with documentation. Vector class will be also nearly complete with the exception of the Vector.integrate() method. More methods might be added to the Vector class at a later stage since it is the central class.

8 July - 21 July : Begin working on the ParamRegion Class and the VectorIntegral class side-by-side. (Please see the description of these classes). The VectorIntegral class and the Vector.integrate() method depend on the ParamRegion class and hence, I'll be trying to get it made first - at least to the point where it can be used to hold some of the basic, if not the more advanced of the methods. Add relevant tests.

By now, we will have a fully working CoordSystem class, a partially (but everything working) Vector class and a sufficiently OK (just-working with half the functionality) ParamRegion class. Also, there would have been some work in the VectorIntergral object (not sure how much, most likely the constructor and maybe the .evalf() method).

21 July - 28 July : Completing the ParamRegion class. This includes the helper methods for the VectorIntegral class. Documentation of ParamRegion class complete. Finalize tests.

Third pull request
Mid term evaluation begins

29 July - 11 August : Finish working on the VectorIntegral class. This includes methods that will reduce the integrals and simplify it to work with the existing SymPy methods. Also, all other methods mentioned in the class description above will also be implemented by this time. Documentation remains.

Fourth pull request

12 August - 1 September : Complete the Vector.integrate method. I would like to devote a little more time to this method, as was discussed earlier. Write documentation for VectorIntegral class. Write tests.

By this point, all the functionality except that related to the RefFrame class will have been implemented and documented. (Refer to class description for more)
Fifth pull request

Now, the only work remaining will be on RefFrame class.

2 September - 15 September : Finish work on the RefFrame. This means all the time based functionality, methods, documentation and tests.

16 September - 23 September : As suggested by Google, this week will go into cleaning up code, giving some final touches to the documentation etc.

Final pull request. Work complete.

References