source: src/Jobs/InterfaceVMGJob.cpp@ 7debff

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 7debff was 7debff, checked in by Frederik Heber <heber@…>, 9 years ago

VMGData additionally stores absolute residual.

  • we check for absolute residual to be less than 1e-5 in any case, otherwise issue a warning.
  • either relative or absolute residual must be less than precision. This is the check used by vmg. Otherwise we may get false failed convergence warnings because not relative but absolute residual reached precision threshold.
  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * InterfaceVMGJob.cpp
26 *
27 * Created on: 10.06.2012
28 * Author: Frederik Heber
29 */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#ifdef HAVE_MPI
36#include "mpi.h"
37#endif
38
39#include "base/vector.hpp"
40#include "base/math.hpp"
41#include "comm/comm.hpp"
42#include "grid/grid.hpp"
43#include "grid/multigrid.hpp"
44#include "units/particle/comm_mpi_particle.hpp"
45#include "units/particle/interpolation.hpp"
46#include "units/particle/linked_cell_list.hpp"
47#include "mg.hpp"
48
49#include "InterfaceVMGJob.hpp"
50
51#include "CodePatterns/MemDebug.hpp"
52
53#include <cmath>
54#include <iostream>
55#include <limits>
56
57#include "CodePatterns/Log.hpp"
58
59#include "Fragmentation/Summation/SetValues/FragmentForces.hpp"
60#include "Jobs/WindowGrid_converter.hpp"
61#include "Jobs/ChargeSmearer.hpp"
62
63using namespace VMG;
64using VMGInterfaces::InterfaceVMGJob;
65
66InterfaceVMGJob::InterfaceVMGJob(const SamplingGrid &_sampled_input,
67 VMGData &_returndata,
68 const std::vector< std::vector<double> > &_particle_positions,
69 const std::vector< double > &_particle_charges,
70 VMG::Boundary boundary,
71 int levelMin,
72 int levelMax,
73 const VMG::Vector &_box_begin,
74 vmg_float _box_end,
75 const int& near_field_cells,
76 const ImportParticles_t _ImportParticles,
77 const bool _DoPrintDebug,
78 const bool _DoSmearCharges,
79 int coarseningSteps,
80 double alpha) :
81 VMG::Interface(boundary, levelMin, levelMax,
82 _box_begin, _box_end, coarseningSteps, alpha),
83 nfc(near_field_cells),
84 meshwidth(Extent(MaxLevel()).MeshWidth().Max()),
85 spl(nfc, meshwidth),
86 sampled_input(_sampled_input),
87 returndata(_returndata),
88 level(levelMax),
89 ImportParticles(_ImportParticles),
90 DoPrintDebug(_DoPrintDebug),
91 OpenBoundaryCondition(boundary[0] == VMG::Open),
92 DoSmearCharges(_DoSmearCharges)
93{
94 for (size_t i=0;i<3;++i) {
95 box_begin[i] = _box_begin[i];
96 box_end[i] = _box_end;
97 }
98 std::vector< std::vector<double> >::const_iterator positer = _particle_positions.begin();
99 std::vector<double>::const_iterator chargeiter = _particle_charges.begin();
100 double pos[3];
101 for (; positer != _particle_positions.end(); ++positer, ++chargeiter) {
102 ASSERT( (*positer).size() == 3,
103 "InterfaceVMGJob::InterfaceVMGJob() - particle "
104 +toString(distance(_particle_positions.begin(), positer))+" has not exactly 3 coordinates.");
105 for (size_t i=0;i<3;++i)
106 pos[i] = (*positer)[i];
107 particles.push_back(Particle::Particle(pos, *chargeiter));
108 }
109}
110
111void InterfaceVMGJob::ImportRightHandSide(Multigrid& multigrid)
112{
113 Index i;
114 Vector pos;
115 // VMG::TempGrid *temp_grid = new VMG::TempGrid(129, 0, 0., 1.);
116
117 Grid& grid = multigrid(multigrid.MaxLevel());
118 grid.Clear();
119 //grid.ClearBoundary(); // we don't have a boundary under periodic boundary conditions
120
121 // print debugging info on grid size
122 LOG(1, "INFO: Mesh has extent " << grid.Extent().MeshWidth() << ".");
123 const int gridpoints = pow(2, level);
124 LOG(1, "INFO: gridpoints on finest level are " << gridpoints << ".");
125 LOG(1, "INFO: "
126 << "X in [" << grid.Local().Begin().X() << "," << grid.Local().End().X() << "],"
127 << "Y in [" << grid.Local().Begin().Y() << "," << grid.Local().End().Y() << "],"
128 << "Z in [" << grid.Local().Begin().Z() << "," << grid.Local().End().Z() << "].");
129
130 /// 1. assign nuclei as smeared-out charges to the grid
131
132 /*
133 * Charge assignment on the grid
134 */
135 Particle::CommMPI& comm = *dynamic_cast<Particle::CommMPI*>(MG::GetComm());
136 Grid& particle_grid = comm.GetParticleGrid();
137 particle_grid.Clear();
138
139 // distribute particles
140 particles.clear();
141 comm.CommParticles(grid, particles);
142
143 assert(particle_grid.Global().LocalSize().IsComponentwiseGreater(
144 VMG::MG::GetFactory().GetObjectStorageVal<int>("PARTICLE_NEAR_FIELD_CELLS")));
145
146 if (ImportParticles == DoImportParticles) {
147 // create smeared-out particle charges on particle_grid via splines
148 LOG(1, "INFO: Creating particle grid for " << particles.size() << " particles.");
149 for (std::list<Particle::Particle>::iterator iter = particles.begin();
150 iter != particles.end(); ++iter) {
151 LOG(2, "DEBUG: Current particle is at " << (*iter).Pos()
152 << " with charge " << (*iter).Charge() << ".");
153 spl.SetSpline(particle_grid, *iter);
154 }
155 }
156
157 // Communicate charges over halo
158 comm.CommFromGhosts(particle_grid);
159
160 if (DoPrintDebug) {
161 // print nuclei grid to vtk
162 comm.PrintGrid(particle_grid, "Sampled Nuclei Density");
163 }
164
165 // add sampled electron charge density onto grid
166 if (DoSmearCharges) {
167 ChargeSmearer &smearer = ChargeSmearer::getInstance();
168 smearer.initializeSplineArray(spl, nfc, meshwidth);
169 }
170 WindowGrid_converter::addWindowOntoGrid(
171 grid,
172 sampled_input,
173 1.,
174 OpenBoundaryCondition,
175 DoSmearCharges);
176
177 if (DoPrintDebug) {
178 // print electron grid to vtk
179 comm.PrintGrid(grid, "Sampled Electron Density");
180 }
181
182 // add particle_grid onto grid
183 for (int i=0; i<grid.Local().Size().X(); ++i)
184 for (int j=0; j<grid.Local().Size().Y(); ++j)
185 for (int k=0; k<grid.Local().Size().Z(); ++k)
186 grid(grid.Local().Begin().X() + i,
187 grid.Local().Begin().Y() + j,
188 grid.Local().Begin().Z() + k) = 4.0 * VMG::Math::pi * (
189 grid(grid.Local().Begin().X() + i,
190 grid.Local().Begin().Y() + j,
191 grid.Local().Begin().Z() + k) +
192 particle_grid.GetVal(particle_grid.Local().Begin().X() + i,
193 particle_grid.Local().Begin().Y() + j,
194 particle_grid.Local().Begin().Z() + k));
195
196 // calculate sum over grid times h^3 as check, should be roughly zero
197 const double element_volume = grid.Extent().MeshWidth().Product();
198 double charge_sum = 0.0;
199 for (Grid::iterator grid_iter = grid.Iterators().Local().Begin();
200 grid_iter != grid.Iterators().Local().End();
201 ++grid_iter)
202 charge_sum += grid.GetVal(*grid_iter);
203 charge_sum = element_volume * comm.GlobalSum(charge_sum);
204 comm.PrintOnce(Debug, "Grid charge integral: %e", charge_sum/(4.0 * VMG::Math::pi));
205
206 if (DoPrintDebug) {
207 // print total grid to vtk
208 comm.PrintGrid(grid, "Total Charge Density");
209 }
210
211// delete temp_grid;
212}
213
214void InterfaceVMGJob::ExportSolution(Grid& grid)
215{
216 /// sample the obtained potential to evaluate with the electron charge density
217
218 // grid now contains the sough-for potential
219 //Comm& comm = *MG::GetComm();
220 Particle::CommMPI& comm = *dynamic_cast<Particle::CommMPI*>(MG::GetComm());
221
222
223 if (DoPrintDebug) {
224 // print output grid to vtk
225 comm.PrintGrid(grid, "Potential Solution");
226 }
227
228 // obtain sampled potential from grid
229 returndata.sampled_potential.setWindow(
230 box_begin,
231 box_end
232 );
233 WindowGrid_converter::addGridOntoWindow(
234 grid,
235 returndata.sampled_potential,
236 +1.,
237 OpenBoundaryCondition
238 );
239
240 // calculate integral over potential as long-range energy contribution
241 const double element_volume =
242 grid.Extent().MeshWidth().X() * grid.Extent().MeshWidth().Y() * grid.Extent().MeshWidth().Z();
243 Grid::iterator grid_iter;
244 double potential_sum = 0.0;
245 for (grid_iter=grid.Iterators().Local().Begin(); grid_iter!=grid.Iterators().Local().End(); ++grid_iter)
246 potential_sum += grid.GetVal(*grid_iter);
247 potential_sum = element_volume * comm.GlobalSum(potential_sum);
248 comm.PrintOnce(Debug, "Grid potential sum: %e", potential_sum);
249
250 {
251 Grid::iterator grid_iter = grid.Iterators().Local().Begin();
252 comm.PrintOnce(Debug, "Grid potential at (0,0,0): %e", grid.GetVal(*grid_iter));
253 }
254
255 //Particle::CommMPI& comm = *dynamic_cast<Particle::CommMPI*>(MG::GetComm()); returndata.e_long = potential_sum;
256
257 /// Calculate potential energy of nuclei
258
259 vmg_float e = 0.0;
260 vmg_float e_long = 0.0;
261 vmg_float e_self = 0.0;
262 vmg_float e_short_peak = 0.0;
263 vmg_float e_short_spline = 0.0;
264
265 Factory& factory = MG::GetFactory();
266
267 /*
268 * Get parameters and arrays
269 */
270 const vmg_int& near_field_cells = factory.GetObjectStorageVal<int>("PARTICLE_NEAR_FIELD_CELLS");
271 const vmg_int& interpolation_degree = factory.GetObjectStorageVal<int>("PARTICLE_INTERPOLATION_DEGREE");
272
273 Particle::Interpolation ip(interpolation_degree);
274
275 const vmg_float r_cut = near_field_cells * grid.Extent().MeshWidth().Max();
276
277 /*
278 * Copy potential values to a grid with sufficiently large halo size.
279 * This may be optimized in future.
280 * The parameters of this grid have been set in the import step.
281 */
282 Grid& particle_grid = comm.GetParticleGrid();
283
284 {
285 Index i;
286 for (i.X()=0; i.X()<grid.Local().Size().X(); ++i.X())
287 for (i.Y()=0; i.Y()<grid.Local().Size().Y(); ++i.Y())
288 for (i.Z()=0; i.Z()<grid.Local().Size().Z(); ++i.Z())
289 particle_grid(i + particle_grid.Local().Begin()) = grid.GetVal(i + grid.Local().Begin());
290 comm.CommToGhosts(particle_grid);
291 }
292
293 /*
294 * Compute potentials
295 */
296 Particle::LinkedCellList lc(particles, near_field_cells, grid);
297 Particle::LinkedCellList::iterator p1, p2;
298 Grid::iterator iter;
299
300 comm.CommLCListToGhosts(lc);
301
302 for (int i=lc.Local().Begin().X(); i<lc.Local().End().X(); ++i)
303 for (int j=lc.Local().Begin().Y(); j<lc.Local().End().Y(); ++j)
304 for (int k=lc.Local().Begin().Z(); k<lc.Local().End().Z(); ++k) {
305
306 if (lc(i,j,k).size() > 0)
307 ip.ComputeCoefficients(particle_grid, Index(i,j,k) - lc.Local().Begin() + particle_grid.Local().Begin());
308
309 for (p1=lc(i,j,k).begin(); p1!=lc(i,j,k).end(); ++p1) {
310
311 // Interpolate long-range part of potential and electric field
312 ip.Evaluate(**p1);
313
314 // Subtract self-induced potential
315 (*p1)->Pot() -= (*p1)->Charge() * spl.GetAntiDerivativeAtZero();
316
317 e_long += 0.5 * (*p1)->Charge() * ip.EvaluatePotentialLR(**p1);
318 e_self += 0.5 * (*p1)->Charge() * (*p1)->Charge() * spl.GetAntiDerivativeAtZero();
319
320 for (int dx=-1*near_field_cells; dx<=near_field_cells; ++dx)
321 for (int dy=-1*near_field_cells; dy<=near_field_cells; ++dy)
322 for (int dz=-1*near_field_cells; dz<=near_field_cells; ++dz) {
323
324 for (p2=lc(i+dx,j+dy,k+dz).begin(); p2!=lc(i+dx,j+dy,k+dz).end(); ++p2)
325
326 if (*p1 != *p2) {
327
328 const Vector dir = (*p1)->Pos() - (*p2)->Pos();
329 const vmg_float length = dir.Length();
330
331 if ((length < r_cut) && (length > std::numeric_limits<double>::epsilon())) {
332
333 (*p1)->Pot() += (*p2)->Charge() / length * (1.0 + spl.EvaluatePotential(length));
334 (*p1)->Field() += (*p2)->Charge() * dir * spl.EvaluateField(length);
335
336 e_short_peak += 0.5 * (*p1)->Charge() * (*p2)->Charge() / length;
337 e_short_spline += 0.5 * (*p1)->Charge() * (*p2)->Charge() / length * spl.EvaluatePotential(length);
338 }
339 }
340 }
341 }
342 }
343
344 const vmg_int& num_particles_local = factory.GetObjectStorageVal<vmg_int>("PARTICLE_NUM_LOCAL");
345
346 /* Remove average force term */
347// if (!particles.empty()) {
348// Vector average_force = 0.0;
349// for (std::list<Particle::Particle>::const_iterator iter=particles.begin(); iter!=particles.end(); ++iter)
350// average_force += iter->Charge() * iter->Field();
351// const vmg_int num_particles_global = comm.GlobalSum(num_particles_local);
352// average_force /= (double)num_particles_global;
353// comm.GlobalSumArray(average_force.vec(), 3);
354// for (std::list<Particle::Particle>::iterator iter=particles.begin(); iter!=particles.end(); ++iter)
355// iter->Field() -= average_force / iter->Charge();
356// comm.PrintOnce(Debug, "Average force term is: %e %e %e", average_force[0], average_force[1], average_force[2]);
357// }
358
359 comm.CommParticlesBack(particles);
360
361 vmg_float* q = factory.GetObjectStorageArray<vmg_float>("PARTICLE_CHARGE_ARRAY");
362 const vmg_float* p = factory.GetObjectStorageArray<vmg_float>("PARTICLE_POTENTIAL_ARRAY");
363 const vmg_float* f = factory.GetObjectStorageArray<vmg_float>("PARTICLE_FIELD_ARRAY");
364
365 // extract forces
366 if (!particles.empty()) {
367 size_t index = 0;
368 returndata.forces.resize(
369 num_particles_local, FragmentForces::force_t(3, 0.) );
370 for (FragmentForces::forces_t::iterator iter = returndata.forces.begin();
371 iter != returndata.forces.end(); ++iter) {
372 comm.PrintOnce(Debug, "%d force vector: %e %e %e", (index/3)+1, f[index+0], f[index+1], f[index+2]);
373 for (size_t i=0;i<3;++i)
374 (*iter)[i] = f[index++];
375 }
376 returndata.hasForces = true;
377 }
378
379 e_long = comm.GlobalSumRoot(e_long);
380 e_short_peak = comm.GlobalSumRoot(e_short_peak);
381 e_short_spline = comm.GlobalSumRoot(e_short_spline);
382 e_self = comm.GlobalSumRoot(e_self);
383
384 for (int j=0; j<num_particles_local; ++j)
385 e += 0.5 * p[j] * q[j];
386 e = comm.GlobalSumRoot(e);
387
388 comm.PrintOnce(Debug, "E_long: %e", e_long);
389 comm.PrintOnce(Debug, "E_short_peak: %e", e_short_peak);
390 comm.PrintOnce(Debug, "E_short_spline: %e", e_short_spline);
391 comm.PrintOnce(Debug, "E_self: %e", e_self);
392 comm.PrintOnce(Debug, "E_total: %e", e);
393 comm.PrintOnce(Debug, "E_total*: %e", e_long + e_short_peak + e_short_spline - e_self);
394
395 returndata.nuclei_long = e_long;
396 returndata.electron_long = e_long;
397
398 // calculate residual
399 const vmg_float& res = factory.GetObjectStorageVal<vmg_float>("RESIDUAL");
400 const vmg_float& init_res = factory.GetObjectStorageVal<vmg_float>("INITIAL_RESIDUAL");
401 const vmg_float& precision = factory.GetObjectStorageVal<vmg_float>("PRECISION");
402 const vmg_float rel_res = (init_res != 0.) ? std::fabs(res / init_res) : 0.;
403 returndata.precision = precision;
404 returndata.residual = res;
405 returndata.relative_residual = rel_res;
406}
Note: See TracBrowser for help on using the repository browser.