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

added test to gradient calculation logic described in #149 #150

Merged
merged 1 commit into from Jun 29, 2017

Conversation

bodduv
Copy link
Collaborator

@bodduv bodduv commented Jun 28, 2017

Edit: I will clean up the QC class with some updated documentation, with several test cases in the subsequent PRs.

in reference to #149 (comment)

Copy link
Collaborator

@davydden davydden left a comment

Choose a reason for hiding this comment

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

i like it, but there is more to do




// Short test to check MoleculeHandler::get_neighbor_lists() function.
Copy link
Collaborator

Choose a reason for hiding this comment

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

is description correct?

auto my_pair_2 = GridTools::find_active_cell_around_point(MappingQ1<dim>(),
dof_handler,
p2);
std::vector<Point<dim>>points = {my_pair_1.second, my_pair_2.second};
Copy link
Collaborator

Choose a reason for hiding this comment

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

space after >. p.s. did you run indentation on this?

ExcInternalError());

const unsigned int dofs_per_cell = fe.dofs_per_cell;
LinearAlgebraDealII::Vector local_gradient_I, local_gradient_II;
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should just be dealii::Vector<double>, it's not a parallel vector.

std::vector<dealii::types::global_dof_index>
local_dof_indices(dofs_per_cell);

FEValues<dim>fe_values(mapping, fe, Quadrature<dim>(points), update_values);
Copy link
Collaborator

Choose a reason for hiding this comment

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

you need to have separate FEValues for each cell. Currently you create a quadrature which has positions of both points inside each cell.

Also add space after >.


for (unsigned int k = 0; k < dofs_per_cell; ++k)
{
local_gradient_I [k] += fe_values.shape_value(k, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

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

you don't do the correct gradient, it should be

n^{ab}*N_i(X^a)

and you need extractors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I thought of doing just one dof at a mesh node first.

Copy link
Collaborator

@davydden davydden Jun 28, 2017

Choose a reason for hiding this comment

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

I thought of doing just one dof

but that's not what i mean and you don't do one dof. You calculate force due to this pair on all dofs currently (for k=0; k < dofs_per_cell; ++k)).

What I am saying is that as far as I can tell this line is wrong.

constraints.distribute_local_to_global(local_gradient_II,
local_dof_indices,
gradient);

Copy link
Collaborator

Choose a reason for hiding this comment

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

at this point we have answer from our favourite approach, now we need to compare it to what we are doing at the moment. Otherwise we don't know if it actually works. The fact that the test compiles and gives you some numbers does not mean yet that it is working 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I compared the values by manual calculation for each dof.

Copy link
Collaborator

@davydden davydden Jun 28, 2017

Choose a reason for hiding this comment

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

but you did not do scalar product n^{ab} * N_i(X^a). i wonder how/why does it work in its current form

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was just comparing the difference of the shape functions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

if you do it correctly, you should probably get the same result as for your cases below n^{ab}={1,0,0}.

p2);
std::vector<Point<dim>>points = {my_pair_1.second, my_pair_2.second};

run(points);
Copy link
Collaborator

Choose a reason for hiding this comment

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

may i suggest to rework it into:

run (const Point<dim> &X1, auto &my_pair_1, const Point<dim> &X2, auto &my_pair_2)

and correct internals accordingly.

Then you should get the same result from your test regardless of the order of points, i.e.

Point<3> p1(0.8,0.8,0.8),p2(1.8,0.8,0.8);
problem.check(p1,p2);

vs

Point<3> p2(0.8,0.8,0.8),p1(1.8,0.8,0.8);
problem.check(p1,p2);

@bodduv
Copy link
Collaborator Author

bodduv commented Jun 28, 2017

I will work on the test again. It appears that I only compared manually the first component. Regarding the older method we didn't finish it to compare to.

Edit: Should I finish the old method and then compare the both?

@davydden
Copy link
Collaborator

davydden commented Jun 28, 2017

I will work on the test again. It appears that I only compared manually the first component.

May I suggest you use Maxima to produce MWE of the standard-QC (blessed output) and choose only 2 points which, however, have Xa-Xb not parallel to any of the axis?

Then you only need to test (pa,pb) vs (pb,pa) vs blessed to make sure it's correct. I don't think you need 3 different pairs to actually test it.

Regarding the older method we didn't finish it to compare to.

that's ok if you have MWE in Maxima or alike.

@davydden
Copy link
Collaborator

davydden commented Jun 28, 2017

I suggest to do 2D as it's easier to test properly in Maxima and also easier to visualize

you can do vectors in Maxima easily:

xa_x: [-R*0.5, R];

depending on how you implement this, you could introduce DoFs for each element

DOFS: [[1,2,...],[2,3,...]];

you can get actual DoFs on the mesh in deal.II from extra output, i.e. https://github.com/dealii/dealii/blob/master/tests/dofs/dof_tools_extract_dofs_with_support_contained_within_01.cc#L90-L113

Here are some examples of how to do for loops in maxima:

N : [1-x,x];
H : [1,1];
nelem : 2;
u1: sin(W*t);
T1: c*t;
nlocaldofs : 2;
DOFS: [[1,2],[2,3]];
M : zeromatrix (3, 3);
K : zeromatrix (3, 3);
R : [0,0,0];
for el:1 thru nelem do
   for i:1 thru nlocaldofs do
     for j:1 thru nlocaldofs do
     (
       ii : DOFS[el][i],
       jj : DOFS[el][j],
       a  : H[el]*integrate(N[i]*N[j],x,0,1),
       b  : (1/H[el])*integrate(diff(N[i],x)*diff(N[j],x),x,0,1),
       M[ii][jj] : M[ii][jj] + a,
       K[ii][jj] : K[ii][jj] + b       
     );
for el:1 thru nelem do
   for i:1 thru nlocaldofs do
     (
       ii : DOFS[el][i],
       a  : H[el]*integrate(N[i],x,0,1),
       R[ii] : R[ii] + a       
     );

Of course, the implementation should be along the standard QC approach where you can evaluate each shape function on any element.

p.s. @vishalkenchan i edited this post to hopefully give enough Maxima syntax to implement the test.

@bodduv
Copy link
Collaborator Author

bodduv commented Jun 28, 2017

Thanks! I will have a look at it tomorrow.

@davydden
Copy link
Collaborator

davydden commented Jun 29, 2017

thinking about this MWE, i would probably proceeded by defining global shape functions for two elements as scalar-valued functions (so that you can evaluate it on any point x,y).

Then, since the vector-valued shape functions in our case are primitive (i.e. F0=[f0,0]; F1=[0,f0], then the scalar products you are after to get forces is essentially: take either first or second component in n^{ab} and multiply with the difference of scalar valued shape functions.

At the end of the day you would have in Maxima x,y components of forces on each node (globally) of 2 element mesh. Knowing how deal.II enumerates DoFs (see above), you would be able to compare the results exactly.

@davydden
Copy link
Collaborator

davydden commented Jun 29, 2017

here's how you can define such shape functions and plot them to make sure it's all good:

N1(x,y):= if x < 1 then (x*y) else (2-x)*y;
plot3d (N1(x,y), [x, 0, 2], [y, 0, 1], [grid, 10, 10],
[mesh_lines_color,false])$

@bodduv
Copy link
Collaborator Author

bodduv commented Jun 29, 2017

Thanks for the code snippets. This makes a sound way to write test.

@bodduv
Copy link
Collaborator Author

bodduv commented Jun 29, 2017

If I am using just FESystem<dim> fe (FE_Q<dim>(1),1);, this would give me scalar valued shape functions right? I could then directly compare the results from maxima. I would be comparing 6 x 3 doubles for 2D case. If I do this, am I still testing what we wanted to test?

@davydden
Copy link
Collaborator

davydden commented Jun 29, 2017

Not really! In dealii u need to use vector-valued function as we use normally. In maxima u will have 2x6 values for forces, in deal.ii the vector will be of size 12. You can easily relate the two if u plot DoFs with the mesh (see above).

for (unsigned int i = 0; i < dof_handler.n_dofs(); i+=dim)
{
for (int d = 0; d < dim; ++d)
std::cout << n[d]*gradient[i] << "\t";
Copy link
Collaborator

Choose a reason for hiding this comment

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

you use vector-valued functions, why don't you just output the gradient itself? I was expecting that you use actual positions of the two points in your run().

Copy link
Collaborator

Choose a reason for hiding this comment

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

see below on how i would rework it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was trying get to the difference of shape function values and comparing before multiplying with the unit normal. But I could do this as well.

Copy link
Collaborator

@davydden davydden Jun 29, 2017

Choose a reason for hiding this comment

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

I am just in favour to do it as close as the actual implementation so that you could just copy-paste this code and add partial_differentive_of_vector_wrt_dofs_02.cc which does exactly the same but using our QC class (with whatever potential and unit cluster weights).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure. I will change it.

//problem.write_dofs_and_support_points_info();
{
Point<2> p1(0.23, 0.37), p2(1.73, 0.43);
problem.check(p1,p2);
Copy link
Collaborator

Choose a reason for hiding this comment

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

please check

problem.check(p2,p1);

dof_handler,
p2);

run (my_pair_1.second, my_pair_2.second);
Copy link
Collaborator

Choose a reason for hiding this comment

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

in order not to assume which point is in which cell, i would provide here my_pair_1, my_pair_2, p1, p2


for (unsigned int k = 0; k < dofs_per_cell; ++k)
{
local_gradient_I [k] = fe_value_a.shape_value(k, 0);
Copy link
Collaborator

@davydden davydden Jun 29, 2017

Choose a reason for hiding this comment

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

Please use extractors and scalar products. Otherwise you may not be doing what you think you are doing.

Copy link
Collaborator

@davydden davydden Jun 29, 2017

Choose a reason for hiding this comment

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

p.s. i don't think this would change the result as shape_value returns

If the shape function is vector-valued, then this returns the only non- zero component

for primitive functions. So i guess it's fine to stick with it, but then at least get which component this corresponds to implement scalar product.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's also how we should implement it in the code in order to avoid multiplications with zeroes.

Copy link
Collaborator

@davydden davydden Jun 29, 2017

Choose a reason for hiding this comment

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

to get what is the only non-zero component for a given shape functions, you would need fe.system_to_component_index(k).first, see dealii/dealii#3646 (comment)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since in our case we have primitive shape functions, could I just do what we are doing in qc.cc:

for (unsigned int k = 0; k < dofs_per_cell; ++k)
  {
    local_gradient_I [k]  =  fe_value_a[u_fe].value(k, 0);
    local_gradient_II [k] = -fe_value_b[u_fe].value(k, 0);
  }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

With scalar product.

Copy link
Collaborator

Choose a reason for hiding this comment

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

no, you misunderstand my point! You need to do

for (unsigned int k = 0; k < dofs_per_cell; ++k)
 {
     const unsigned int comp = fe.system_to_component_index(k).first;
     local_gradient_I [k]  = nab[comp] * fe_value_a.shape_value(k, 0);
 }

Copy link
Collaborator

@davydden davydden Jun 29, 2017

Choose a reason for hiding this comment

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

that would be the actual (TODO) implementation in QC class. Otherwise we will do 2 out of 3 multiplications with zeroes (in 3D case).

Copy link
Collaborator

@davydden davydden left a comment

Choose a reason for hiding this comment

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

nice, minor changes to make it closer to the actual (TODO) implementation.

Copy link
Collaborator

@davydden davydden left a comment

Choose a reason for hiding this comment

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

nice, i guess we are now fully convinced that this approach works! 😄

@davydden davydden merged commit 3f7990f into ltm-erlangen:master Jun 29, 2017
@bodduv
Copy link
Collaborator Author

bodduv commented Jun 29, 2017

👍

@bodduv bodduv deleted the fix/gradient_monoatomic branch June 29, 2017 18:28
@davydden
Copy link
Collaborator

davydden commented Jun 29, 2017

@vishalkenchan i would now add another test (together with MWE in Maxima) and use this logic in QC to calculate forces from two cluster atoms (say spring potential) for the same mesh.

The MWE in Maxima is the same up to dE/dr * (n1+n2)/2 multiplier which you can hard-code according to the chosen potential E and cluster weights n1 and n2.

@bodduv
Copy link
Collaborator Author

bodduv commented Jun 29, 2017

Are you going to touch compute_energy_gradient()? In this case, I will work on something else (probably address some of the issues in #118).

@davydden
Copy link
Collaborator

I meant that it's the next logical step for u to do ;-)

@davydden
Copy link
Collaborator

@vishalkenchan i will look at doing forces in QC, but not necessarily test it ;-)

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

2 participants