Skip to content
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

Generalize the classes to use complex or real numbers #21

Open
wants to merge 12 commits into
base: v2.x
Choose a base branch
from

Conversation

PabloIbannez
Copy link
Contributor

No description provided.

@@ -42,39 +42,40 @@ namespace uammd{
namespace BVP{

namespace detail{
template <typename U>
class SubsystemSolver{
int nz;
real H;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is leaving this as real a conscious decision?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we believe that since H is associated with a size, it will always be real. Furthermore, in the complex_bvp branch (which is the branch we're trying to merge into the main one with these changes), H is treated as a real number, while all other entities are complex.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first I though this PR was making some things compatible with either float or double, thus some of my comments -.-
Calling the template parameter U seems to signal that this class can be instantiated with any type (like float, float4, complex...). I guess this is why concepts were introduced in C++20, so you can restrict the type to be either thrust::complex or real and nothing else.
I now remember I did not merge the complex branch because I found no way to state this clearly via code.
The code for the complex and real versions is really similar but not quite so. I considered making everything complex, but many usecases are real and that would entail twice the work.
Maybe putting everything into a hidden namespace and just exposing two instantiated types (real and thrust::complex) for the public API is the best way to go. Then if you want to use another complex type or whatever you know you are on your own.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am really scared of the changes to this file. cufftComplex types are just an alias to float2 or double2. thrust::complex actually has the correct complex algebra.
By defining complex to thrust::complex you changed the behavior of any line that does something like:

complex a,b = ...
complex c = a*b;

@RaulPPelaez
Copy link
Owner

Could you comment on what you did here?
Did you ran the tests for these components locally?

@RaulPPelaez
Copy link
Owner

I did something really similar when I needed the BVP solver to run with complex:
v2.x...complex_bvp
But in that case I wrote it to be compatible just with complex and using thrust::complex.

My point is this function here:

    //Given A (2x2 matrix) and b as two numbers of an arbitrary type (could be complex, real...)
    template<class T, class T2>
    __device__ thrust::pair<T,T> solve2x2System(T2 A[4], thrust::pair<T,T> b){
      const auto det  = A[0]*A[3] - A[1]*A[2];
      const T c0 = (b.first*A[3] - A[1]*b.second)/det;
      const T d0 = (b.second*A[0] - b.first*A[2])/det;
      return thrust::make_pair(c0, d0);
    }

Is incorrect if the type passed to it is cufftComplex instead of thrust::complex.

@RaulPPelaez
Copy link
Owner

For instance, these tests might fail, since they define complex with cufftComplex:
https://github.com/RaulPPelaez/UAMMD/blob/v2.x/test/misc/bvp/bvp.cu

@PabloPalaciosAlonso
Copy link
Contributor

I did something really similar when I needed the BVP solver to run with complex: v2.x...complex_bvp But in that case I wrote it to be compatible just with complex and using thrust::complex.

My point is this function here:

    //Given A (2x2 matrix) and b as two numbers of an arbitrary type (could be complex, real...)
    template<class T, class T2>
    __device__ thrust::pair<T,T> solve2x2System(T2 A[4], thrust::pair<T,T> b){
      const auto det  = A[0]*A[3] - A[1]*A[2];
      const T c0 = (b.first*A[3] - A[1]*b.second)/det;
      const T d0 = (b.second*A[0] - b.first*A[2])/det;
      return thrust::make_pair(c0, d0);
    }

Is incorrect if the type passed to it is cufftComplex instead of thrust::complex.

I see your point, probably this function is a copy-paste of what you did in BVP_complex. One solution could be to specialize this function for the most common complex types?

@RaulPPelaez
Copy link
Owner

I am not sure that is worth it. There are probably other places in which the code is expecting either cufftComplex or thrust::complex, and the difference there are super tricky and subtle.
For instance this code here will be broken in a very subtle and mostly silent way if you do not use thrust::complex and the waveVector is complex:

const real kH2 = k*k*H*H;

Same here:
auto B00 = -k*k*H*H;
auto B11 = -k*k*H*H;

I would say these classes should work as is with thrust::complex and something should be done to ensure they cannot be instantiated with cufftComplex.

For starters, the tests in here related to the BVP solver should be included as part of this PR, those tests include complex and are super thorough. We cannot trust these changes unless that passes. Sadly they have to be ran locally since github CI machines do not have GPUs.

Most of these classes are internal implementation details and should typically not be instantiated by users of the library. One solution here could be to make these classes a template:

class BoundaryValueProblemSolver{

class BatchedBVPHandler{

Call them something like name_impl and then generate two aliases like:

using BVPSolverComplex = BVPSolver_impl<thrust::complex<real>>;
using BVPSolverReal = BVPSolver_impl<real>;

This at least signals that you are not supposed to instantiate _impl with just about any type.
Any option is ok as long as the documentation reflects it. You can modify the documentation for these components here:
https://github.com/RaulPPelaez/UAMMD/blob/v2.x/docs/BoundaryValueProblemSolver.rst

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants