-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP : Vector module #2208
Closed
Closed
WIP : Vector module #2208
Changes from all commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
5a86cbd
Started off with the project. CoordSys super class been worked on,
ea4f464
More conversion methods, helpers addded
b18c234
Added Vector, VectAdd, VectMul
ef7f16b
Added some more helpers for the separate method
0ede0a9
Corrected separate functions to return dict
3a9a3bb
Fixed some typos, a few helpers
38616f5
Added arithmatic methods, some more helpers.
07cdc4b
Merge remote-tracking branch 'upstream/master' into vector
8c69063
Changed the design so that base scalar and base vectors cannot be
d109843
Merge remote-tracking branch 'upstream/master' into vector
f9cd6f8
Added some more helpers for `express` method.
58e8212
Merge remote-tracking branch 'upstream/master' into vector
9dccbef
Position is now a vector. Some basic funcitonality is working.
4edc216
Merge remote-tracking branch 'upstream/master' into vector
5437537
Corrected many small errors, bugs. Added ZeroVector
41653d3
Merge remote-tracking branch 'upstream/master' into vector
df4dc80
Fixed some methods
d175318
Started to clean up vector.py
gilbertgede 8c75640
Changes to BaseScalar
gilbertgede 9151bd0
Removed extraneous function in Vector
gilbertgede 2303c97
Introduced BaseVector class.
gilbertgede 5c07b6a
Rectified certain errors
srjoglekar246 bf92b9f
Changed the implementation of many methods. Also, changed the separat…
80b1e19
Merge branch 'vector' into vector_temp
2cf396a
Made several changes to the express method. Added some helpers of
58a1900
Merge remote-tracking branch 'upstream/master' into vector
d7a0529
Merge remote-tracking branch 'upstream/master' into vector
74b103c
Merge remote-tracking branch 'origin/vector' into vector
c20ca69
Added more helpers for the express method
3deb413
Added helpers for changing base vectors and for base scalars.
4adeb0b
Completed express - testing remains.
4a0abbb
Merge remote-tracking branch 'upstream/master' into vector
2aac647
Added a grad method. Added a few helpers.
2113754
Merge remote-tracking branch 'upstream/master' into vector
e1767cd
Added a method for cross product of vectors along with requied helpers.
2f90523
Added methods for div, curl, laplacian with some minor changes.
ae81fe0
Added the paramregion.py file. Started working on the ParamRegion class.
03b6afd
Renamed param_region.py to integrate.py
3af44d8
Added differentiation method for vector. Did some work on Surface
0461abe
Started performing tests.
15cd547
Merge remote-tracking branch 'upstream/master' into vector
aff8d75
Fixed several bugs in the testing.
a7bcb78
Changed args to be ()
28cb657
Added _hashable_content to BaseScalar and BaseVector.
bd79374
Added some temporary hacks to make things work for a test.
047c772
Initial version of express method now works.\
73fee43
Express method is finally working.
2f4e1e3
The dot and cross methods work now.
2e9f9b6
Merge remote-tracking branch 'upstream/master' into vector
e202558
The orientation methods are working now.
e2e02c2
Added docstrings and doctests.
e5be839
Merge remote-tracking branch 'upstream/master' into vector
bdfcc78
Added more docsrtings and doctests. Corrected the orientnew method.
4606ac5
Added more docstrings and doctests.
c8ff5dd
Merge remote-tracking branch 'upstream/master' into vector
07f810c
Made some changes to posnew method
d75be68
Added a flag in the definition of CoordSys.
0a0cfd7
Merge remote-tracking branch 'upstream/master' into vector
5b10aa8
Divergence now working.
e742bbb
Merge remote-tracking branch 'upstream/master' into vector
6211d3e
The grad method is now working.
f36c3e0
Curl of a vector is now working correctly.
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from vector import (base_scalars, vectors, dot, cross, _all_coordinate_systems, | ||
_separate_to_vectors, express, is_const_vect) | ||
|
||
from vector import (BaseScalar, CoordSys, CoordSysRect, CoordSysCyl, | ||
CoordSysSph, Vector, VectAdd, VectMul, ZeroVector, BaseVector) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
from sympy.core import (Basic, Expr, Symbol, symbols, sympify, diff, Pow, Mul, | ||
Add, S) | ||
from sympy.integrals.integrals import integrate, Integral | ||
from sympy.vector.vector import (_all_coordinate_systems, _all_base_scalars, | ||
_vect_add, _vect_mul, _coord_sys_scalar_list, | ||
_has_base_scalar) | ||
from sympy.vector.vector import (dot, cross, express, grad, div, curl, | ||
laplacian) | ||
from sympy.vector.vector import (BaseScalar, Vector, BaseVector, VectMul, | ||
ZeroVector) | ||
|
||
|
||
class ParamRegion(object): | ||
""" | ||
A class to represent parametric region in space | ||
""" | ||
def __init__(self, params, coord_sys, definition, bounds): | ||
""" | ||
Create a ParamRegion object to represent a parametrically defined | ||
region in space. | ||
params : A tuple of length <=2. Both elements of the tuple are symbols | ||
that act as parameters. | ||
coord_sys : an instance of subclass of the CoordSys class. | ||
definition : a tuple of length 3. Each element corresponds to the | ||
paramentric definition of the BaseScalars for the coord_sys | ||
bounds : a tuple of 2 tuples. Each inner tuple has 2 elements which | ||
act as bounds for the Symbols in params, respectively. | ||
""" | ||
# sanity check | ||
if not len(params) <= 2: | ||
raise ValueError("params should be a tuple of length 2") | ||
if(not isinstance(params[0], Symbol) or | ||
not isinstance(params[1], Symbol)): | ||
raise ValueError("all elements of params should be SymPy Symbols") | ||
if not len(definition) == 3: | ||
raise ValueError("definition is a tuple of length 3") | ||
|
||
# Let's call the first parameter 'u' and the second 'v' | ||
if len(params) == 1: | ||
self._u = params[0] | ||
elif len(params) == 2: | ||
self._u = params[0] | ||
self._v = params[1] | ||
|
||
self.coord_sys = coord_sys | ||
self.definition = definition | ||
|
||
@property | ||
def u(self): | ||
return self._u | ||
|
||
@property | ||
def v(self): | ||
return self._v | ||
|
||
|
||
class VectIntegral(object): | ||
""" | ||
Base class for representing different type of integrals of vector fields. | ||
Not to be initialized directly by the user. | ||
""" | ||
def __init__(self, vect, param_region): | ||
self.vect = vect | ||
self.param_region = param_region | ||
|
||
# More methods that are common to all vector integral classes will go here. | ||
|
||
|
||
class LineVectIntegral(VectIntegral): | ||
""" | ||
A container for holding line intergrals of vector fields. | ||
Holds the vector field and the ParamRegion objects. | ||
|
||
Not to be initialized directly. An instance of this class is returned | ||
by the integrate method on vectors. | ||
""" | ||
def __init__(self, vect, param_region, coord_sys): | ||
# The integral must be of the type F.dl | ||
super(LineVectIntegral, self).__init__(vect, param_region) | ||
|
||
def eval(self): | ||
""" | ||
Evaluate the integral symbolically, if possible. Else, return the | ||
LineVectIntegral object back. | ||
""" | ||
vect = self.vect.express(self.param_region.coord_sys) | ||
# calculate the differential length element for coord_sys | ||
dl = self.param_region.coord_sys.h_list | ||
base_scalars = self.param_region.coord_sys.base_scalars | ||
# Calculate differntials for each of the elements of dl using | ||
# the definitions in the param_region object | ||
# Also note that because this is a F.dl type integral, therefore, | ||
# there is only one parameter; self.param_region. | ||
for i in range(len(dl)): | ||
dl[i] = diff(self.param_region.definition[i], self.param_region.u) | ||
|
||
# Now since vect and dl are in the same coorfinates, we have: | ||
comp = vect.components | ||
expr = S.Zero | ||
for i in range(len(dl)): | ||
expr = expr + (comp[i] * dl[i]) | ||
# Now, expr has been completely express in coord_sys. We just need to | ||
# change everything to the parametric variable, 'u' | ||
for i, scalar in enumerate(base_scalars): | ||
subs_dict = {scalar: self.param_region.definition[i]} | ||
expr = expr.subs(subs_dict) | ||
|
||
# Now, we can integrate the expression just as any regular integral | ||
bounds = self.param_region.bounds | ||
res = integrate(expr, | ||
(self.param_region.u, bounds[0][0], bounds[0][1])) | ||
if not isinstance(res, Integral): | ||
return res | ||
return self | ||
|
||
|
||
class SurfaceVectIntegral(VectIntegral): | ||
""" | ||
A container for holding surface intergrals of vector fields. | ||
Holds the vector field and the ParamRegion objects. | ||
|
||
Not to be initialized directly. An instance of this class is returned | ||
by the integrate method on vectors. | ||
""" | ||
def __init__(self, vect, param_region): | ||
# The integral must be of the type F.dl | ||
super(LineVectIntegral, self).__init__(vect, param_region) | ||
|
||
def eval(self): | ||
vect = self.vect.express(self.param_region.coord_sys) | ||
# First, we need to calculate dS (differntial surface element vector) | ||
# if r(u, v) is the position vector of any point on the surface | ||
# normal = (d/du)r x (d/dv)r | ||
r = ZeroVector | ||
base_vectors = self.param_region.coord_sys.base_vectors | ||
for i in range(len(base_vectors)): | ||
r = r + self.param_region.definitions[i] * base_vectors[i] | ||
|
||
r = r.expand() | ||
r_u = r.diff(self.param_region.u) | ||
r_v = r.diff(self.param_region.v) | ||
|
||
# TODO : Implement normalize | ||
n = cross(r_u, r_v) | ||
# http://en.wikipedia.org/wiki/Surface_integral | ||
vect_dot_n = dot(vect, n, self.param_region.coord_sys.param_region) | ||
|
||
# Now we need to calculate double_integral( vect_dot_n du dv ) | ||
bounds = self.param_region.bounds | ||
|
||
# Check the bounds to ascertain the order | ||
# Case 1 : Both bounds are constants - can perform either order | ||
# Case 2 : Bounds for u are in terms of v : integrate wrt to u first | ||
# Case 3 : Bounds for v are in terms of u : integrate wrt to v first | ||
case = _bounds_case(bounds, self.param_region.u, self.param_region.v) | ||
if case == 1 or case == 2: | ||
res = integrate(vect_dot_n, | ||
(self.param_region.u, bounds[0][0], bounds[0][1]), | ||
(self.param_region.v, bounds[1][0], bounds[1][1])) | ||
if not isinstance(res, Integral): | ||
return res | ||
elif case == 2: | ||
return self | ||
|
||
if case == 1 or case == 3: | ||
res = integrate(vect_dot_n, | ||
(self.param_region.v, bounds[0][0], bounds[0][1]), | ||
(self.param_region.u, bounds[1][0], bounds[1][1])) | ||
if not isinstance(res, Integral): | ||
return res | ||
|
||
# Integral couldn't be evaluated | ||
return self | ||
|
||
def _bounds_case(bounds, u, v): | ||
""" | ||
Check whether the given bounds depend on variables of integration and | ||
return the correct case. | ||
""" | ||
# Check bounds of u for v | ||
lower = bounds[0][0] | ||
upper = bounds[0][1] | ||
|
||
atoms_lower = lower.atoms() | ||
atoms_upper = upper.atoms() | ||
if atoms_lower.issuperset(set([v])) or atoms_upper.issuperset(set([v])): | ||
return 2 | ||
|
||
# Check bounds of v for u | ||
lower = bounds[1][0] | ||
upper = bounds[1][1] | ||
|
||
atoms_lower = lower.atoms() | ||
atoms_upper = upper.atoms() | ||
if atoms_lower.issuperset(set([u])) or atoms_upper.issuperset(set([u])): | ||
return 3 | ||
|
||
# No bounds occur in the other. Bounds are constants. | ||
return 1 | ||
|
||
def vect_integrate(vect, param_region): | ||
""" | ||
Takes an object with is_Vector == True and a ParamRegion object and | ||
retuns an instance of the appropriate subclass of VectIntegral class. | ||
vect : an is_Vector == True object | ||
param_region : a ParamRegion object | ||
coord_sys : an instance of subclass of CoordSys class | ||
""" | ||
# First check if type of the integral | ||
if hasattr(param_region, '_u') and not hasattr(param_region, '_v'): | ||
# Integral is of type F.dl | ||
obj = LineVectIntegral(vect, param_region) | ||
elif hasattr(param_region, '_u') and hasattr(param_region, '_v'): | ||
# Integral is a of type F.dS (surface integral) | ||
obj = SurfaceVectIntegral(vect, param_region) | ||
# We can also consider cases with scalar*vector type integral | ||
# TODO: Implement the above comment | ||
return obj |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that @srjoglekar246 said:
I do not see why you need this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are making it a part of the SymPy architecture, its better to do this, I think. It makes my code (as well as Prasoon's) more consistent with the rest of SymPy's handling of Basic entities, in the sense of using 'if instance.is_Something:'
Does this create any problems that we may be overlooking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any good reason not to use
isinstance
? The problem is that you should not need to change the superclass when writing a new subclass.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't any problem as such, we just decided to follow convention. As I recall, for eg, is_Boolean, is_Not were added to Basic when the logic module was formed. This is just on the lines of that. We could remove the line, if you insist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the way it's been done in SymPy. Whether this design decision is a good one or not is beside this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not know why these flags were added, but if you do not have a reason to write something it is better not to write it. In the same way, if you do not know why a convention is put in place do not follow it blindly. Most of those
is_*
flags are there as workaround for bad class structure.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine to not add this. isinstance is better.